#include "Base/v3d_exception.h"
#include "Geometry/v3d_poseutilities.h"
#include "Math/v3d_linear_lu.h"
#include "Math/v3d_linear_tnt.h"
#include "Math/v3d_mathutilities.h"
#include "Math/v3d_optimization.h"

#include <cmath>
#include <cassert>

using namespace std;

namespace
{

   using namespace V3D;

//----------------------------------------------------------------------
// Five-point related code
//----------------------------------------------------------------------

   inline void
   getNullSpace(double const * x1, double const * y1, double const * x2, double const * y2, double * EE)
   {
      Matrix<double> equation(5, 9); // 5*9 equations.

      for (int i = 0; i < 5; ++i)
      {
         equation[i][0] = x1[i]*x2[i];
         equation[i][1] = y1[i]*x2[i];
         equation[i][2] = x2[i];

         equation[i][3] = x1[i]*y2[i];
         equation[i][4] = y1[i]*y2[i];
         equation[i][5] = y2[i];

         equation[i][6] = x1[i];
         equation[i][7] = y1[i];
         equation[i][8] = 1;
      }

      // NOTE: TNT's SVD requires #rows >= #columns, so create a square equation matrix by filling in zeros.
      Matrix<double> A(9, 9);
      makeZeroMatrix(A);
      for (int i = 0; i < 5; ++i)
         for (int j = 0; j < 9; ++j)
            A[i][j] = equation[i][j];

      SVD<double> svd(A);

      Matrix<double> const V = svd.getV();

      if (0) {
//          cout << "getNullSpace: " << endl;
         cout << "A = "; displayMatrix(A);
//          cout << "V = "; displayMatrix(V);

         Vector<double> col(9);
         Matrix<double> N(9, 4);
         V.getColumnSlice(0, 9, 5, col); N.setColumnSlice(0, 9, 0, col);
         V.getColumnSlice(0, 9, 6, col); N.setColumnSlice(0, 9, 1, col);
         V.getColumnSlice(0, 9, 7, col); N.setColumnSlice(0, 9, 2, col);
         V.getColumnSlice(0, 9, 8, col); N.setColumnSlice(0, 9, 3, col);

          cout << "N = "; displayMatrix(N);

//          Matrix<double> tmp(5, 4);
//          multiply_A_B(equation, N, tmp);
//          displayMatrix(tmp);
      }

      //displayMatrix(V);

      // Copy the last 4 columns of U
      for (int i = 0; i < 4; ++i)
      {
         for(int j = 0; j < 9; ++j)
            EE[i*9+j] = V[j][5+i];
      }
   } // end getNullSpace()

   // This is from the MEX helper file for the 5-point source available at http://vis.uky.edu/%7Estewe/FIVEPOINT/.
   // FIXME: We might want to create our own coefficients using Maxima etc.
   inline void
   extractCubicCoefficients(double * EE, double * A)
   {
      double e00,e01,e02,e03,e04,e05,e06,e07,e08;
      double e10,e11,e12,e13,e14,e15,e16,e17,e18;
      double e20,e21,e22,e23,e24,e25,e26,e27,e28;
      double e30,e31,e32,e33,e34,e35,e36,e37,e38;

      double e002,e012,e022,e032,e042,e052,e062,e072,e082;
      double e102,e112,e122,e132,e142,e152,e162,e172,e182;
      double e202,e212,e222,e232,e242,e252,e262,e272,e282;
      double e302,e312,e322,e332,e342,e352,e362,e372,e382;

      double e003,e013,e023,e033,e043,e053,e063,e073,e083;
      double e103,e113,e123,e133,e143,e153,e163,e173,e183;
      double e203,e213,e223,e233,e243,e253,e263,e273,e283;
      double e303,e313,e323,e333,e343,e353,e363,e373,e383;

      e00 = EE[0*9 + 0 ];
      e10 = EE[1*9 + 0 ];
      e20 = EE[2*9 + 0 ];
      e30 = EE[3*9 + 0 ];
      e01 = EE[0*9 + 1 ];
      e11 = EE[1*9 + 1 ];
      e21 = EE[2*9 + 1 ];
      e31 = EE[3*9 + 1 ];
      e02 = EE[0*9 + 2 ];
      e12 = EE[1*9 + 2 ];
      e22 = EE[2*9 + 2 ];
      e32 = EE[3*9 + 2 ];
      e03 = EE[0*9 + 3 ];
      e13 = EE[1*9 + 3 ];
      e23 = EE[2*9 + 3 ];
      e33 = EE[3*9 + 3 ];
      e04 = EE[0*9 + 4 ];
      e14 = EE[1*9 + 4 ];
      e24 = EE[2*9 + 4 ];
      e34 = EE[3*9 + 4 ];
      e05 = EE[0*9 + 5 ];
      e15 = EE[1*9 + 5 ];
      e25 = EE[2*9 + 5 ];
      e35 = EE[3*9 + 5 ];
      e06 = EE[0*9 + 6 ];
      e16 = EE[1*9 + 6 ];
      e26 = EE[2*9 + 6 ];
      e36 = EE[3*9 + 6 ];
      e07 = EE[0*9 + 7 ];
      e17 = EE[1*9 + 7 ];
      e27 = EE[2*9 + 7 ];
      e37 = EE[3*9 + 7 ];
      e08 = EE[0*9 + 8 ];
      e18 = EE[1*9 + 8 ];
      e28 = EE[2*9 + 8 ];
      e38 = EE[3*9 + 8 ];

      e002 =e00*e00;
      e102 =e10*e10;
      e202 =e20*e20;
      e302 =e30*e30;
      e012 =e01*e01;
      e112 =e11*e11;
      e212 =e21*e21;
      e312 =e31*e31;
      e022 =e02*e02;
      e122 =e12*e12;
      e222 =e22*e22;
      e322 =e32*e32;
      e032 =e03*e03;
      e132 =e13*e13;
      e232 =e23*e23;
      e332 =e33*e33;
      e042 =e04*e04;
      e142 =e14*e14;
      e242 =e24*e24;
      e342 =e34*e34;
      e052 =e05*e05;
      e152 =e15*e15;
      e252 =e25*e25;
      e352 =e35*e35;
      e062 =e06*e06;
      e162 =e16*e16;
      e262 =e26*e26;
      e362 =e36*e36;
      e072 =e07*e07;
      e172 =e17*e17;
      e272 =e27*e27;
      e372 =e37*e37;
      e082 =e08*e08;
      e182 =e18*e18;
      e282 =e28*e28;
      e382 =e38*e38;

      e003 =e00*e00*e00;
      e103 =e10*e10*e10;
      e203 =e20*e20*e20;
      e303 =e30*e30*e30;
      e013 =e01*e01*e01;
      e113 =e11*e11*e11;
      e213 =e21*e21*e21;
      e313 =e31*e31*e31;
      e023 =e02*e02*e02;
      e123 =e12*e12*e12;
      e223 =e22*e22*e22;
      e323 =e32*e32*e32;
      e033 =e03*e03*e03;
      e133 =e13*e13*e13;
      e233 =e23*e23*e23;
      e333 =e33*e33*e33;
      e043 =e04*e04*e04;
      e143 =e14*e14*e14;
      e243 =e24*e24*e24;
      e343 =e34*e34*e34;
      e053 =e05*e05*e05;
      e153 =e15*e15*e15;
      e253 =e25*e25*e25;
      e353 =e35*e35*e35;
      e063 =e06*e06*e06;
      e163 =e16*e16*e16;
      e263 =e26*e26*e26;
      e363 =e36*e36*e36;
      e073 =e07*e07*e07;
      e173 =e17*e17*e17;
      e273 =e27*e27*e27;
      e373 =e37*e37*e37;
      e083 =e08*e08*e08;
      e183 =e18*e18*e18;
      e283 =e28*e28*e28;
      e383 =e38*e38*e38;


      A[0 + 10*0]=0.5*e003+0.5*e00*e012+0.5*e00*e022+0.5*e00*e032+e03*e01*e04+e03*e02*e05+0.5*e00*e062+e06*e01*e07+e06*e02*e08-0.5*e00*e042-0.5*e00*e052-0.5*e00*e072-0.5*e00*e082;
      A[0 + 10*1]=e00*e11*e01+e00*e12*e02+e03*e00*e13+e03*e11*e04+e03*e01*e14+e03*e12*e05+e03*e02*e15+e13*e01*e04+e13*e02*e05+e06*e00*e16+1.5*e10*e002+0.5*e10*e012+0.5*e10*e022+0.5*e10*e062-0.5*e10*e042-0.5*e10*e052-0.5*e10*e072+0.5*e10*e032+e06*e11*e07+e06*e01*e17+e06*e12*e08+e06*e02*e18+e16*e01*e07+e16*e02*e08-e00*e14*e04-e00*e17*e07-e00*e15*e05-e00*e18*e08-0.5*e10*e082;
      A[0 + 10*2]=e16*e02*e18+e03*e12*e15+e10*e11*e01+e10*e12*e02+e03*e10*e13+e03*e11*e14+e13*e11*e04+e13*e01*e14+e13*e12*e05+e13*e02*e15+e06*e10*e16+e06*e12*e18+e06*e11*e17+e16*e11*e07+e16*e01*e17+e16*e12*e08-e10*e14*e04-e10*e17*e07-e10*e15*e05-e10*e18*e08+1.5*e00*e102+0.5*e00*e122+0.5*e00*e112+0.5*e00*e132+0.5*e00*e162-0.5*e00*e152-0.5*e00*e172-0.5*e00*e182-0.5*e00*e142;
      A[0 + 10*3]=0.5*e103+0.5*e10*e122+0.5*e10*e112+0.5*e10*e132+e13*e12*e15+e13*e11*e14+0.5*e10*e162+e16*e12*e18+e16*e11*e17-0.5*e10*e152-0.5*e10*e172-0.5*e10*e182-0.5*e10*e142;
      A[0 + 10*4]=-e00*e28*e08-e00*e25*e05-e00*e27*e07-e00*e24*e04+e26*e02*e08+e26*e01*e07+e06*e02*e28+e06*e22*e08+e06*e01*e27+e06*e21*e07+e23*e02*e05+e23*e01*e04+e03*e02*e25+e03*e22*e05+e03*e01*e24+e03*e21*e04+e00*e22*e02+e00*e21*e01-0.5*e20*e082-0.5*e20*e052-0.5*e20*e072-0.5*e20*e042+e06*e00*e26+0.5*e20*e062+e03*e00*e23+0.5*e20*e022+1.5*e20*e002+0.5*e20*e032+0.5*e20*e012;
      A[0 + 10*5]=-e10*e24*e04-e10*e27*e07-e10*e25*e05-e10*e28*e08-e20*e14*e04-e20*e17*e07-e20*e15*e05-e20*e18*e08-e00*e24*e14-e00*e25*e15-e00*e27*e17-e00*e28*e18+e06*e21*e17+e06*e22*e18+e06*e12*e28+e16*e00*e26+e16*e21*e07+e16*e01*e27+e16*e22*e08+e16*e02*e28+e26*e11*e07+e26*e01*e17+e26*e12*e08+e26*e02*e18+e06*e11*e27+e23*e11*e04+e23*e01*e14+e23*e12*e05+e23*e02*e15+e06*e20*e16+e06*e10*e26+e03*e21*e14+e03*e22*e15+e03*e12*e25+e13*e00*e23+e13*e21*e04+e13*e01*e24+e13*e22*e05+e13*e02*e25+e03*e11*e24+e03*e20*e13+e03*e10*e23+e00*e21*e11+3*e00*e20*e10+e00*e22*e12+e20*e12*e02+e20*e11*e01+e10*e22*e02+e10*e21*e01;
      A[0 + 10*6]=-0.5*e20*e152+e26*e11*e17-e10*e24*e14-e10*e25*e15-e10*e27*e17-e10*e28*e18+0.5*e20*e162+e13*e10*e23+e13*e22*e15+e23*e12*e15+e23*e11*e14+e16*e10*e26+e16*e21*e17+e16*e11*e27+e16*e22*e18+e16*e12*e28+e26*e12*e18+e13*e12*e25+0.5*e20*e132+1.5*e20*e102+0.5*e20*e122+0.5*e20*e112+e10*e21*e11+e10*e22*e12+e13*e11*e24-0.5*e20*e172-0.5*e20*e182-0.5*e20*e142+e13*e21*e14;
      A[0 + 10*7]=-e20*e25*e05-e20*e28*e08-0.5*e00*e272-0.5*e00*e282-0.5*e00*e242+0.5*e00*e262-0.5*e00*e252+e06*e20*e26+0.5*e00*e232+e06*e22*e28+e06*e21*e27+e26*e21*e07+e26*e01*e27+e26*e22*e08+e26*e02*e28-e20*e24*e04-e20*e27*e07+e03*e20*e23+e03*e22*e25+e03*e21*e24+e23*e21*e04+e23*e01*e24+e23*e22*e05+e23*e02*e25+e20*e21*e01+e20*e22*e02+1.5*e00*e202+0.5*e00*e222+0.5*e00*e212;
      A[0 + 10*8]=e23*e21*e14+e23*e11*e24+e23*e22*e15+e23*e12*e25+e16*e20*e26+e16*e22*e28+e16*e21*e27+e26*e21*e17+e26*e11*e27+e26*e22*e18+e26*e12*e28+1.5*e10*e202+0.5*e10*e222+0.5*e10*e212+0.5*e10*e232+e20*e21*e11+e20*e22*e12+e13*e20*e23+e13*e22*e25+e13*e21*e24-e20*e24*e14-e20*e25*e15-e20*e27*e17-e20*e28*e18-0.5*e10*e272-0.5*e10*e282-0.5*e10*e242-0.5*e10*e252+0.5*e10*e262;
      A[0 + 10*9]=0.5*e203+0.5*e20*e222+0.5*e20*e212+0.5*e20*e232+e23*e22*e25+e23*e21*e24+0.5*e20*e262+e26*e22*e28+e26*e21*e27-0.5*e20*e252-0.5*e20*e272-0.5*e20*e282-0.5*e20*e242;
      A[0 + 10*10]=e06*e32*e08-0.5*e30*e082-0.5*e30*e042-0.5*e30*e052-0.5*e30*e072+0.5*e30*e012+0.5*e30*e022+0.5*e30*e032+0.5*e30*e062+1.5*e30*e002+e00*e31*e01+e00*e32*e02+e03*e31*e04+e03*e01*e34+e03*e32*e05+e03*e02*e35+e33*e01*e04+e33*e02*e05+e06*e00*e36+e06*e31*e07+e06*e01*e37+e06*e02*e38+e36*e01*e07+e36*e02*e08-e00*e34*e04-e00*e37*e07-e00*e35*e05-e00*e38*e08+e03*e00*e33;
      A[0 + 10*11]=e06*e30*e16+e03*e30*e13+e16*e31*e07+e06*e10*e36-e10*e37*e07+3*e00*e30*e10+e00*e32*e12-e00*e38*e18-e10*e34*e04-e10*e35*e05-e10*e38*e08-e30*e14*e04-e30*e17*e07-e30*e15*e05-e30*e18*e08+e00*e31*e11+e10*e31*e01+e10*e32*e02+e30*e11*e01+e30*e12*e02+e03*e10*e33-e00*e34*e14-e00*e35*e15-e00*e37*e17+e03*e31*e14+e03*e11*e34+e03*e32*e15+e03*e12*e35+e13*e00*e33+e13*e31*e04+e13*e01*e34+e13*e32*e05+e13*e02*e35+e33*e11*e04+e33*e01*e14+e33*e12*e05+e33*e02*e15+e06*e31*e17+e06*e11*e37+e06*e32*e18+e06*e12*e38+e16*e00*e36+e16*e01*e37+e16*e32*e08+e16*e02*e38+e36*e11*e07+e36*e01*e17+e36*e12*e08+e36*e02*e18;
      A[0 + 10*12]=e13*e10*e33+e33*e11*e14+e16*e10*e36+e16*e31*e17+e16*e11*e37+e16*e32*e18+e16*e12*e38+e36*e12*e18+e36*e11*e17-e10*e34*e14-e10*e35*e15-e10*e37*e17-e10*e38*e18+e10*e31*e11+e10*e32*e12+e13*e31*e14+e13*e11*e34+e13*e32*e15+e13*e12*e35+e33*e12*e15+1.5*e30*e102+0.5*e30*e122+0.5*e30*e112+0.5*e30*e132+0.5*e30*e162-0.5*e30*e152-0.5*e30*e172-0.5*e30*e182-0.5*e30*e142;
      A[0 + 10*13]=e00*e32*e22+3*e00*e30*e20+e00*e31*e21+e20*e31*e01+e20*e32*e02+e30*e21*e01+e30*e22*e02+e03*e20*e33+e03*e32*e25+e03*e22*e35+e03*e31*e24+e03*e21*e34+e23*e00*e33+e23*e31*e04+e23*e01*e34+e23*e32*e05+e23*e02*e35+e33*e21*e04+e33*e01*e24+e33*e22*e05+e33*e02*e25+e06*e30*e26+e06*e20*e36+e06*e32*e28+e06*e22*e38+e06*e31*e27+e06*e21*e37+e26*e00*e36+e26*e31*e07+e03*e30*e23+e26*e01*e37+e26*e32*e08+e26*e02*e38+e36*e21*e07+e36*e01*e27+e36*e22*e08+e36*e02*e28-e00*e35*e25-e00*e37*e27-e00*e38*e28-e00*e34*e24-e20*e34*e04-e20*e37*e07-e20*e35*e05-e20*e38*e08-e30*e24*e04-e30*e27*e07-e30*e25*e05-e30*e28*e08;
      A[0 + 10*14]=e16*e30*e26+e13*e21*e34+3*e10*e30*e20+e10*e32*e22+e10*e31*e21+e20*e31*e11+e20*e32*e12+e30*e21*e11+e30*e22*e12+e13*e30*e23+e13*e20*e33+e13*e32*e25+e13*e22*e35+e13*e31*e24+e23*e10*e33+e23*e31*e14+e23*e11*e34+e23*e32*e15+e23*e12*e35+e33*e21*e14+e33*e11*e24+e33*e22*e15+e33*e12*e25+e16*e20*e36+e16*e32*e28+e16*e22*e38+e16*e31*e27+e16*e21*e37+e26*e10*e36+e26*e31*e17+e26*e11*e37+e26*e32*e18+e26*e12*e38+e36*e21*e17+e36*e11*e27+e36*e22*e18+e36*e12*e28-e10*e35*e25-e10*e37*e27-e10*e38*e28-e10*e34*e24-e20*e34*e14-e20*e35*e15-e20*e37*e17-e20*e38*e18-e30*e24*e14-e30*e25*e15-e30*e27*e17-e30*e28*e18;
      A[0 + 10*15]=-e20*e34*e24+0.5*e30*e262-0.5*e30*e252-0.5*e30*e272-0.5*e30*e282-0.5*e30*e242+1.5*e30*e202+0.5*e30*e222+0.5*e30*e212+0.5*e30*e232+e20*e32*e22+e20*e31*e21+e23*e20*e33+e23*e32*e25+e23*e22*e35+e23*e31*e24+e23*e21*e34+e33*e22*e25+e33*e21*e24+e26*e20*e36+e26*e32*e28+e26*e22*e38+e26*e31*e27+e26*e21*e37+e36*e22*e28+e36*e21*e27-e20*e35*e25-e20*e37*e27-e20*e38*e28;
      A[0 + 10*16]=0.5*e00*e322+e30*e32*e02+e30*e31*e01+1.5*e00*e302+0.5*e00*e312+e03*e32*e35+e33*e31*e04+e33*e01*e34+e33*e32*e05+e33*e02*e35+e06*e30*e36+e06*e31*e37+e06*e32*e38+e36*e31*e07+e36*e01*e37+e36*e32*e08+e36*e02*e38-e30*e34*e04-e30*e37*e07-e30*e35*e05-e30*e38*e08+0.5*e00*e332+0.5*e00*e362-0.5*e00*e382-0.5*e00*e352-0.5*e00*e342-0.5*e00*e372+e03*e30*e33+e03*e31*e34;
      A[0 + 10*17]=0.5*e10*e362-0.5*e10*e382-0.5*e10*e352-0.5*e10*e342-0.5*e10*e372+e36*e31*e17+e36*e11*e37+e36*e32*e18+e36*e12*e38-e30*e34*e14-e30*e35*e15-e30*e37*e17-e30*e38*e18+1.5*e10*e302+0.5*e10*e312+0.5*e10*e322+0.5*e10*e332+e30*e31*e11+e30*e32*e12+e13*e30*e33+e13*e31*e34+e13*e32*e35+e33*e31*e14+e33*e11*e34+e33*e32*e15+e33*e12*e35+e16*e30*e36+e16*e31*e37+e16*e32*e38;
      A[0 + 10*18]=e33*e31*e24+e33*e21*e34+e26*e30*e36+e26*e31*e37+e26*e32*e38+e36*e32*e28+e36*e22*e38+e36*e31*e27+e36*e21*e37-e30*e35*e25-e30*e37*e27-e30*e38*e28-e30*e34*e24+e33*e22*e35+1.5*e20*e302+0.5*e20*e312+0.5*e20*e322+0.5*e20*e332+0.5*e20*e362-0.5*e20*e382-0.5*e20*e352-0.5*e20*e342-0.5*e20*e372+e30*e32*e22+e30*e31*e21+e23*e30*e33+e23*e31*e34+e23*e32*e35+e33*e32*e25;
      A[0 + 10*19]=0.5*e303+0.5*e30*e312+0.5*e30*e322+0.5*e30*e332+e33*e31*e34+e33*e32*e35+0.5*e30*e362+e36*e31*e37+e36*e32*e38-0.5*e30*e382-0.5*e30*e352-0.5*e30*e342-0.5*e30*e372;
      A[1 + 10*0]=e00*e01*e04+0.5*e002*e03+e00*e02*e05+0.5*e033+0.5*e03*e042+0.5*e03*e052+0.5*e03*e062+e06*e04*e07+e06*e05*e08-0.5*e03*e012-0.5*e03*e072-0.5*e03*e022-0.5*e03*e082;
      A[1 + 10*1]=e03*e14*e04+e10*e01*e04+e16*e05*e08+e00*e10*e03+e00*e11*e04+e00*e01*e14+e00*e12*e05+e00*e02*e15+e10*e02*e05+e03*e15*e05+e06*e03*e16+e06*e14*e07+e06*e04*e17+e06*e15*e08+e06*e05*e18+0.5*e002*e13+1.5*e13*e032+0.5*e13*e042+0.5*e13*e052+0.5*e13*e062-0.5*e13*e012-0.5*e13*e072-0.5*e13*e022-0.5*e13*e082+e16*e04*e07-e03*e12*e02-e03*e11*e01-e03*e17*e07-e03*e18*e08;
      A[1 + 10*2]=-e13*e11*e01+e00*e10*e13+e00*e12*e15+e00*e11*e14+e10*e11*e04+e10*e01*e14+e10*e12*e05+e10*e02*e15+e13*e14*e04+e13*e15*e05+e06*e13*e16+e06*e15*e18+e06*e14*e17+e16*e14*e07+e16*e04*e17+e16*e15*e08+e16*e05*e18-e13*e12*e02-e13*e17*e07-e13*e18*e08+0.5*e102*e03+1.5*e03*e132+0.5*e03*e152+0.5*e03*e142+0.5*e03*e162-0.5*e03*e112-0.5*e03*e172-0.5*e03*e122-0.5*e03*e182;
      A[1 + 10*3]=0.5*e102*e13+e10*e11*e14+e10*e12*e15+0.5*e133+0.5*e13*e152+0.5*e13*e142+0.5*e13*e162+e16*e15*e18+e16*e14*e17-0.5*e13*e112-0.5*e13*e122-0.5*e13*e172-0.5*e13*e182;
      A[1 + 10*4]=-e03*e28*e08-e03*e27*e07-e03*e21*e01-e03*e22*e02+e26*e05*e08+e26*e04*e07+e06*e05*e28+e06*e25*e08+e06*e04*e27+e06*e24*e07+e03*e25*e05+e03*e24*e04+e20*e02*e05+e20*e01*e04+e00*e02*e25+e00*e22*e05+e00*e01*e24+e00*e21*e04+e00*e20*e03-0.5*e23*e072-0.5*e23*e082-0.5*e23*e022-0.5*e23*e012+e06*e03*e26+0.5*e23*e052+0.5*e23*e062+1.5*e23*e032+0.5*e23*e042+0.5*e002*e23;
      A[1 + 10*5]=e00*e21*e14+e00*e11*e24+e00*e10*e23+e00*e22*e15+e00*e12*e25+e20*e12*e05+e20*e01*e14+e20*e11*e04+e00*e20*e13+e10*e02*e25+e10*e22*e05+e10*e01*e24+e10*e21*e04+e10*e20*e03+e23*e15*e05+e23*e14*e04+e13*e25*e05+e13*e24*e04+e03*e24*e14+e03*e25*e15+3*e03*e23*e13+e20*e02*e15+e16*e03*e26+e06*e14*e27-e23*e18*e08+e06*e24*e17+e06*e15*e28+e06*e25*e18+e06*e13*e26+e06*e23*e16+e26*e04*e17+e26*e14*e07+e16*e05*e28+e16*e25*e08+e16*e04*e27+e16*e24*e07-e03*e22*e12-e03*e21*e11+e26*e05*e18+e26*e15*e08-e03*e27*e17-e03*e28*e18-e13*e22*e02-e13*e28*e08-e13*e27*e07-e13*e21*e01-e23*e17*e07-e23*e11*e01-e23*e12*e02;
      A[1 + 10*6]=-0.5*e23*e182-0.5*e23*e172-0.5*e23*e112-0.5*e23*e122-e13*e22*e12-e13*e27*e17-e13*e28*e18+e26*e15*e18+e26*e14*e17-e13*e21*e11+e20*e12*e15+e13*e25*e15+e13*e24*e14+e16*e13*e26+e16*e25*e18+e16*e15*e28+e16*e24*e17+e16*e14*e27+1.5*e23*e132+0.5*e23*e152+0.5*e23*e142+0.5*e23*e162+e10*e20*e13+e10*e21*e14+e10*e11*e24+e10*e22*e15+e10*e12*e25+e20*e11*e14+0.5*e102*e23;
      A[1 + 10*7]=e26*e04*e27+e00*e22*e25-e23*e28*e08+0.5*e03*e262-0.5*e03*e212-0.5*e03*e272-0.5*e03*e222-0.5*e03*e282+e23*e24*e04+e23*e25*e05+0.5*e202*e03+e06*e23*e26+e06*e24*e27+e06*e25*e28+e26*e24*e07+e26*e25*e08+e26*e05*e28-e23*e22*e02-e23*e21*e01-e23*e27*e07+e00*e20*e23+e00*e21*e24+e20*e21*e04+e20*e01*e24+e20*e22*e05+e20*e02*e25+1.5*e03*e232+0.5*e03*e242+0.5*e03*e252;
      A[1 + 10*8]=e20*e11*e24-0.5*e13*e212-0.5*e13*e272-0.5*e13*e222-0.5*e13*e282-e23*e27*e17-e23*e28*e18+e26*e25*e18+e26*e24*e17+e26*e14*e27-e23*e21*e11-e23*e22*e12+e26*e15*e28+e23*e25*e15+e23*e24*e14+e16*e23*e26+e16*e24*e27+e16*e25*e28+0.5*e13*e262+e20*e21*e14+e20*e22*e15+e20*e12*e25+0.5*e13*e242+0.5*e13*e252+0.5*e202*e13+1.5*e13*e232+e10*e20*e23+e10*e22*e25+e10*e21*e24;
      A[1 + 10*9]=0.5*e202*e23+e20*e22*e25+e20*e21*e24+0.5*e233+0.5*e23*e242+0.5*e23*e252+0.5*e23*e262+e26*e24*e27+e26*e25*e28-0.5*e23*e212-0.5*e23*e272-0.5*e23*e222-0.5*e23*e282;
      A[1 + 10*10]=e00*e30*e03+0.5*e33*e062-0.5*e33*e012-0.5*e33*e022-0.5*e33*e072+e03*e35*e05+e06*e03*e36+e06*e34*e07+e06*e04*e37+e06*e35*e08+e06*e05*e38+e36*e04*e07+e36*e05*e08-e03*e32*e02-e03*e31*e01-e03*e37*e07+e00*e31*e04+e00*e01*e34+e00*e32*e05+e00*e02*e35+e30*e01*e04+e30*e02*e05+e03*e34*e04-e03*e38*e08+0.5*e002*e33+1.5*e33*e032+0.5*e33*e042+0.5*e33*e052-0.5*e33*e082;
      A[1 + 10*11]=e06*e35*e18+e06*e33*e16+e00*e30*e13+e00*e10*e33+e00*e31*e14+e00*e11*e34+e00*e32*e15+e00*e12*e35+e10*e30*e03-e33*e17*e07-e33*e18*e08+e10*e31*e04+e10*e01*e34+e10*e32*e05+e10*e02*e35+e30*e11*e04+e30*e01*e14+e30*e12*e05+e30*e02*e15+3*e03*e33*e13+e03*e35*e15+e03*e34*e14+e13*e34*e04+e13*e35*e05+e33*e14*e04+e33*e15*e05+e06*e13*e36+e06*e15*e38+e06*e34*e17+e06*e14*e37+e16*e03*e36+e16*e34*e07+e16*e04*e37+e16*e35*e08+e16*e05*e38+e36*e14*e07+e36*e04*e17+e36*e15*e08+e36*e05*e18-e03*e31*e11-e03*e32*e12-e03*e37*e17-e03*e38*e18-e13*e32*e02-e13*e31*e01-e13*e37*e07-e13*e38*e08-e33*e12*e02-e33*e11*e01;
      A[1 + 10*12]=e16*e13*e36+e10*e11*e34+0.5*e33*e152+0.5*e33*e142+0.5*e33*e162-0.5*e33*e112-0.5*e33*e122-0.5*e33*e172-0.5*e33*e182+0.5*e102*e33+1.5*e33*e132+e10*e30*e13+e10*e31*e14+e10*e32*e15+e10*e12*e35+e30*e11*e14+e30*e12*e15+e13*e35*e15+e13*e34*e14+e16*e35*e18+e16*e15*e38+e16*e34*e17+e16*e14*e37+e36*e15*e18+e36*e14*e17-e13*e31*e11-e13*e32*e12-e13*e37*e17-e13*e38*e18;
      A[1 + 10*13]=e06*e35*e28+e36*e04*e27+e00*e20*e33+e00*e30*e23+3*e03*e33*e23+e03*e34*e24+e03*e35*e25+e23*e34*e04+e23*e35*e05+e33*e24*e04+e33*e25*e05+e06*e33*e26+e06*e23*e36+e06*e34*e27+e06*e24*e37+e06*e25*e38+e26*e03*e36+e26*e34*e07+e26*e04*e37+e26*e35*e08+e26*e05*e38+e36*e24*e07+e36*e25*e08+e36*e05*e28-e03*e31*e21-e03*e37*e27-e03*e32*e22-e03*e38*e28-e23*e32*e02-e23*e31*e01-e23*e37*e07-e23*e38*e08-e33*e22*e02-e33*e21*e01-e33*e27*e07-e33*e28*e08+e00*e32*e25+e00*e22*e35+e00*e31*e24+e00*e21*e34+e20*e30*e03+e20*e31*e04+e20*e01*e34+e20*e32*e05+e20*e02*e35+e30*e21*e04+e30*e01*e24+e30*e22*e05+e30*e02*e25;
      A[1 + 10*14]=e10*e30*e23+e10*e20*e33+e10*e22*e35+e10*e32*e25+e10*e31*e24+e10*e21*e34+e20*e30*e13+e20*e31*e14+e20*e11*e34+e20*e32*e15+e20*e12*e35+e30*e21*e14+e30*e11*e24+e30*e22*e15+e30*e12*e25+3*e13*e33*e23+e13*e34*e24+e13*e35*e25+e23*e35*e15+e23*e34*e14+e33*e25*e15+e33*e24*e14+e16*e33*e26+e16*e23*e36+e16*e34*e27+e16*e24*e37+e16*e35*e28+e16*e25*e38+e26*e13*e36+e26*e35*e18+e26*e15*e38+e26*e34*e17+e26*e14*e37+e36*e25*e18+e36*e15*e28+e36*e24*e17+e36*e14*e27-e13*e31*e21-e13*e37*e27-e13*e32*e22-e13*e38*e28-e23*e31*e11-e23*e32*e12-e23*e37*e17-e23*e38*e18-e33*e21*e11-e33*e22*e12-e33*e27*e17-e33*e28*e18;
      A[1 + 10*15]=-0.5*e33*e212-0.5*e33*e272-0.5*e33*e222-0.5*e33*e282+e26*e23*e36+e20*e30*e23+e20*e32*e25+e20*e22*e35+e20*e31*e24+e20*e21*e34+e30*e22*e25+e30*e21*e24+e23*e34*e24+e23*e35*e25+e26*e34*e27+e26*e24*e37+e26*e35*e28+e26*e25*e38+e36*e24*e27+e36*e25*e28-e23*e31*e21-e23*e37*e27-e23*e32*e22-e23*e38*e28+0.5*e202*e33+1.5*e33*e232+0.5*e33*e242+0.5*e33*e252+0.5*e33*e262;
      A[1 + 10*16]=e33*e35*e05+e30*e32*e05+0.5*e03*e362+0.5*e302*e03+1.5*e03*e332+0.5*e03*e352+0.5*e03*e342+e00*e30*e33+e00*e31*e34+e00*e32*e35+e30*e31*e04+e30*e01*e34+e30*e02*e35+e33*e34*e04+e06*e33*e36+e06*e35*e38+e06*e34*e37+e36*e34*e07+e36*e04*e37+e36*e35*e08+e36*e05*e38-e33*e32*e02-e33*e31*e01-e33*e37*e07-e33*e38*e08-0.5*e03*e322-0.5*e03*e382-0.5*e03*e312-0.5*e03*e372;
      A[1 + 10*17]=-e33*e31*e11-e33*e32*e12-e33*e38*e18+e30*e11*e34+e30*e32*e15+e30*e12*e35+e33*e35*e15+e33*e34*e14+e16*e33*e36+e16*e35*e38+e16*e34*e37+e36*e35*e18+e36*e15*e38+e36*e34*e17+e36*e14*e37-e33*e37*e17+0.5*e302*e13+1.5*e13*e332+0.5*e13*e352+0.5*e13*e342+0.5*e13*e362-0.5*e13*e322-0.5*e13*e382-0.5*e13*e312-0.5*e13*e372+e10*e30*e33+e10*e31*e34+e10*e32*e35+e30*e31*e14;
      A[1 + 10*18]=e36*e25*e38+0.5*e302*e23+1.5*e23*e332+0.5*e23*e352+0.5*e23*e342+0.5*e23*e362-0.5*e23*e322-0.5*e23*e382-0.5*e23*e312-0.5*e23*e372+e20*e30*e33+e20*e31*e34+e20*e32*e35+e30*e32*e25+e30*e22*e35+e30*e31*e24+e30*e21*e34+e33*e34*e24+e33*e35*e25+e26*e33*e36+e26*e35*e38+e26*e34*e37+e36*e34*e27+e36*e24*e37+e36*e35*e28-e33*e31*e21-e33*e37*e27-e33*e32*e22-e33*e38*e28;
      A[1 + 10*19]=0.5*e302*e33+e30*e31*e34+e30*e32*e35+0.5*e333+0.5*e33*e352+0.5*e33*e342+0.5*e33*e362+e36*e35*e38+e36*e34*e37-0.5*e33*e322-0.5*e33*e382-0.5*e33*e312-0.5*e33*e372;
      A[2 + 10*0]=0.5*e002*e06+e00*e01*e07+e00*e02*e08+0.5*e032*e06+e03*e04*e07+e03*e05*e08+0.5*e063+0.5*e06*e072+0.5*e06*e082-0.5*e06*e012-0.5*e06*e022-0.5*e06*e042-0.5*e06*e052;
      A[2 + 10*1]=e00*e10*e06+0.5*e002*e16+0.5*e032*e16+1.5*e16*e062+0.5*e16*e072+0.5*e16*e082-0.5*e16*e012-0.5*e16*e022-0.5*e16*e042-0.5*e16*e052+e00*e11*e07+e00*e01*e17+e00*e12*e08+e00*e02*e18+e10*e01*e07+e10*e02*e08+e03*e13*e06+e03*e14*e07+e03*e04*e17+e03*e15*e08+e03*e05*e18+e13*e04*e07+e13*e05*e08+e06*e17*e07+e06*e18*e08-e06*e12*e02-e06*e11*e01-e06*e14*e04-e06*e15*e05;
      A[2 + 10*2]=e13*e14*e07+0.5*e102*e06+e00*e10*e16+e00*e12*e18+e00*e11*e17+e10*e11*e07+e10*e01*e17+e10*e12*e08+e10*e02*e18+e03*e13*e16+e03*e15*e18+e03*e14*e17+e13*e04*e17+e13*e15*e08+e13*e05*e18+e16*e17*e07+e16*e18*e08-e16*e12*e02-e16*e11*e01-e16*e14*e04-e16*e15*e05+0.5*e132*e06+1.5*e06*e162+0.5*e06*e182+0.5*e06*e172-0.5*e06*e112-0.5*e06*e122-0.5*e06*e142-0.5*e06*e152;
      A[2 + 10*3]=0.5*e102*e16+e10*e12*e18+e10*e11*e17+0.5*e132*e16+e13*e15*e18+e13*e14*e17+0.5*e163+0.5*e16*e182+0.5*e16*e172-0.5*e16*e112-0.5*e16*e122-0.5*e16*e142-0.5*e16*e152;
      A[2 + 10*4]=e06*e27*e07+e23*e05*e08+e23*e04*e07+e03*e05*e28+e03*e25*e08+e03*e04*e27+e03*e24*e07+e20*e02*e08+e20*e01*e07+e00*e02*e28+e00*e22*e08+e00*e01*e27+e00*e21*e07+e00*e20*e06-e06*e25*e05-e06*e24*e04-e06*e21*e01-e06*e22*e02+e06*e28*e08-0.5*e26*e042-0.5*e26*e052-0.5*e26*e012-0.5*e26*e022+0.5*e26*e082+0.5*e26*e072+1.5*e26*e062+0.5*e002*e26+e03*e23*e06+0.5*e032*e26;
      A[2 + 10*5]=e13*e05*e28+e00*e12*e28+e13*e25*e08+e13*e04*e27+e13*e24*e07+e13*e23*e06+e03*e14*e27+e03*e24*e17+e03*e15*e28+e03*e25*e18+e03*e13*e26+e03*e23*e16+e20*e02*e18+e20*e12*e08+e20*e01*e17+e20*e11*e07+e00*e21*e17+e10*e02*e28+e10*e22*e08+e10*e01*e27+e10*e21*e07+e10*e20*e06+e00*e11*e27-e26*e15*e05-e26*e14*e04-e26*e11*e01-e26*e12*e02-e16*e25*e05-e16*e24*e04-e16*e21*e01-e16*e22*e02-e06*e24*e14-e06*e22*e12-e06*e21*e11-e06*e25*e15+e00*e20*e16+e00*e22*e18+e00*e10*e26+e26*e18*e08+e26*e17*e07+e16*e28*e08+e16*e27*e07+e06*e27*e17+e06*e28*e18+3*e06*e26*e16+e23*e05*e18+e23*e15*e08+e23*e04*e17+e23*e14*e07;
      A[2 + 10*6]=e10*e22*e18+0.5*e26*e182+0.5*e26*e172+e16*e28*e18+e16*e27*e17-e16*e25*e15-e16*e21*e11-e16*e22*e12+1.5*e26*e162+e13*e15*e28+e13*e24*e17+e13*e14*e27+e23*e15*e18+e23*e14*e17+e10*e12*e28+e10*e21*e17+e10*e11*e27+e20*e12*e18+e20*e11*e17+e13*e23*e16+e13*e25*e18+e10*e20*e16+0.5*e102*e26-0.5*e26*e122-0.5*e26*e142-0.5*e26*e152-e16*e24*e14-0.5*e26*e112+0.5*e132*e26;
      A[2 + 10*7]=-0.5*e06*e212-0.5*e06*e252-0.5*e06*e242+0.5*e06*e272+0.5*e06*e282-0.5*e06*e222+e20*e02*e28+e03*e23*e26+e03*e24*e27+e03*e25*e28+e23*e24*e07+e23*e04*e27+e23*e25*e08+e23*e05*e28+e26*e28*e08-e26*e22*e02-e26*e21*e01-e26*e24*e04-e26*e25*e05+e26*e27*e07+e00*e20*e26+e00*e21*e27+e00*e22*e28+e20*e21*e07+e20*e01*e27+e20*e22*e08+0.5*e202*e06+0.5*e232*e06+1.5*e06*e262;
      A[2 + 10*8]=-e26*e24*e14-0.5*e16*e212-0.5*e16*e252-0.5*e16*e242-e26*e25*e15-0.5*e16*e222-e26*e21*e11+e26*e28*e18+e26*e27*e17-e26*e22*e12+e23*e15*e28+e23*e24*e17+e23*e14*e27+0.5*e232*e16+1.5*e16*e262+0.5*e16*e272+0.5*e16*e282+e10*e20*e26+e10*e21*e27+e10*e22*e28+e20*e22*e18+e20*e12*e28+e20*e21*e17+e20*e11*e27+e13*e23*e26+e13*e24*e27+e13*e25*e28+e23*e25*e18+0.5*e202*e16;
      A[2 + 10*9]=0.5*e202*e26+e20*e21*e27+e20*e22*e28+0.5*e232*e26+e23*e24*e27+e23*e25*e28+0.5*e263+0.5*e26*e272+0.5*e26*e282-0.5*e26*e222-0.5*e26*e212-0.5*e26*e252-0.5*e26*e242;
      A[2 + 10*10]=e03*e34*e07+0.5*e032*e36+1.5*e36*e062+e03*e33*e06+e00*e31*e07+e00*e01*e37+e00*e32*e08+e00*e02*e38+e30*e01*e07+e30*e02*e08+e03*e04*e37+e03*e35*e08+e03*e05*e38+0.5*e002*e36-0.5*e36*e022-0.5*e36*e042-0.5*e36*e052+0.5*e36*e072+0.5*e36*e082-0.5*e36*e012+e33*e04*e07+e33*e05*e08+e06*e37*e07+e06*e38*e08-e06*e32*e02-e06*e31*e01-e06*e34*e04-e06*e35*e05+e00*e30*e06;
      A[2 + 10*11]=e13*e33*e06+e13*e34*e07+e13*e04*e37+e13*e35*e08+e13*e05*e38+e33*e14*e07+e33*e04*e17+e33*e15*e08+e33*e05*e18+3*e06*e36*e16+e06*e38*e18+e06*e37*e17+e16*e37*e07+e16*e38*e08+e36*e17*e07+e36*e18*e08-e06*e35*e15-e06*e31*e11-e06*e32*e12+e00*e31*e17+e00*e11*e37+e10*e30*e06+e10*e31*e07+e10*e01*e37+e10*e32*e08+e10*e02*e38+e30*e11*e07+e30*e01*e17+e30*e12*e08+e30*e02*e18+e03*e33*e16+e03*e13*e36+e03*e35*e18+e03*e15*e38+e03*e34*e17+e03*e14*e37+e00*e30*e16+e00*e12*e38-e06*e34*e14-e16*e32*e02-e16*e31*e01-e16*e34*e04-e16*e35*e05-e36*e12*e02-e36*e11*e01-e36*e14*e04-e36*e15*e05+e00*e10*e36+e00*e32*e18;
      A[2 + 10*12]=0.5*e36*e182+0.5*e36*e172-0.5*e36*e112-0.5*e36*e122-0.5*e36*e142-0.5*e36*e152+0.5*e102*e36+0.5*e132*e36+1.5*e36*e162+e10*e30*e16+e10*e32*e18+e10*e12*e38+e10*e31*e17+e10*e11*e37+e30*e12*e18+e30*e11*e17+e13*e33*e16+e13*e35*e18+e13*e15*e38+e13*e34*e17+e13*e14*e37+e33*e15*e18+e33*e14*e17+e16*e38*e18+e16*e37*e17-e16*e35*e15-e16*e31*e11-e16*e32*e12-e16*e34*e14;
      A[2 + 10*13]=e00*e20*e36+e00*e31*e27+e00*e21*e37+e00*e32*e28+e00*e22*e38+e20*e30*e06+e20*e31*e07+e20*e01*e37+e20*e32*e08+e20*e02*e38+e30*e21*e07+e30*e01*e27+e30*e22*e08+e30*e02*e28+e03*e33*e26+e03*e23*e36+e03*e34*e27+e03*e24*e37+e03*e35*e28-e26*e31*e01-e26*e35*e05-e36*e22*e02-e36*e21*e01-e36*e24*e04-e36*e25*e05-e26*e34*e04+e03*e25*e38+e23*e34*e07+e23*e04*e37+e23*e35*e08+e23*e05*e38+e33*e24*e07+e33*e04*e27+e33*e25*e08+e33*e05*e28+3*e06*e36*e26+e06*e37*e27+e06*e38*e28+e26*e37*e07+e26*e38*e08+e36*e27*e07+e36*e28*e08-e06*e32*e22-e06*e31*e21-e06*e35*e25-e06*e34*e24-e26*e32*e02+e00*e30*e26+e23*e33*e06;
      A[2 + 10*14]=e10*e30*e26+e10*e20*e36+e10*e31*e27+e10*e21*e37+e10*e32*e28+e10*e22*e38+e20*e30*e16+e20*e32*e18+e20*e12*e38+e20*e31*e17+e20*e11*e37+e30*e22*e18+e30*e12*e28+e30*e21*e17+e30*e11*e27+e13*e33*e26+e13*e23*e36+e13*e34*e27+e13*e24*e37+e13*e35*e28+e13*e25*e38+e23*e33*e16+e23*e35*e18+e23*e15*e38+e23*e34*e17+e23*e14*e37+e33*e25*e18+e33*e15*e28+e33*e24*e17+e33*e14*e27+3*e16*e36*e26+e16*e37*e27+e16*e38*e28+e26*e38*e18+e26*e37*e17+e36*e28*e18+e36*e27*e17-e16*e32*e22-e16*e31*e21-e16*e35*e25-e16*e34*e24-e26*e35*e15-e26*e31*e11-e26*e32*e12-e26*e34*e14-e36*e25*e15-e36*e21*e11-e36*e22*e12-e36*e24*e14;
      A[2 + 10*15]=e33*e25*e28+e20*e30*e26+e20*e32*e28+e20*e31*e27+e20*e21*e37+e20*e22*e38+e30*e21*e27+e30*e22*e28+e23*e33*e26+e23*e34*e27+e23*e24*e37+e23*e35*e28+e23*e25*e38+e33*e24*e27+e26*e37*e27+e26*e38*e28-e26*e32*e22-e26*e31*e21-e26*e35*e25-e26*e34*e24+0.5*e202*e36+0.5*e232*e36+1.5*e36*e262+0.5*e36*e272+0.5*e36*e282-0.5*e36*e222-0.5*e36*e212-0.5*e36*e252-0.5*e36*e242;
      A[2 + 10*16]=e00*e30*e36+e00*e32*e38+e00*e31*e37+e30*e31*e07+e30*e01*e37+e30*e32*e08+e30*e02*e38+e03*e33*e36-0.5*e06*e342+e03*e35*e38+e33*e34*e07+e33*e04*e37+e33*e35*e08+e33*e05*e38+e36*e37*e07+e36*e38*e08-e36*e32*e02-e36*e31*e01-e36*e34*e04-e36*e35*e05+e03*e34*e37+0.5*e302*e06+0.5*e332*e06+1.5*e06*e362+0.5*e06*e382+0.5*e06*e372-0.5*e06*e352-0.5*e06*e312-0.5*e06*e322;
      A[2 + 10*17]=-e36*e35*e15+e10*e30*e36+0.5*e302*e16+0.5*e332*e16+1.5*e16*e362+0.5*e16*e382+0.5*e16*e372-0.5*e16*e352-0.5*e16*e312-0.5*e16*e322-0.5*e16*e342+e10*e32*e38+e10*e31*e37+e30*e32*e18+e30*e12*e38+e30*e31*e17+e30*e11*e37+e13*e33*e36+e13*e35*e38+e13*e34*e37+e33*e35*e18+e33*e15*e38+e33*e34*e17+e33*e14*e37+e36*e38*e18+e36*e37*e17-e36*e31*e11-e36*e32*e12-e36*e34*e14;
      A[2 + 10*18]=-e36*e35*e25+e30*e32*e28+0.5*e302*e26+0.5*e332*e26+1.5*e26*e362+0.5*e26*e382+0.5*e26*e372-0.5*e26*e352-0.5*e26*e312-0.5*e26*e322-0.5*e26*e342+e20*e30*e36+e20*e32*e38+e20*e31*e37+e30*e31*e27+e30*e21*e37+e30*e22*e38+e23*e33*e36+e23*e35*e38+e23*e34*e37+e33*e34*e27+e33*e24*e37+e33*e35*e28+e33*e25*e38+e36*e37*e27+e36*e38*e28-e36*e32*e22-e36*e31*e21-e36*e34*e24;
      A[2 + 10*19]=0.5*e302*e36+e30*e32*e38+e30*e31*e37+0.5*e332*e36+e33*e35*e38+e33*e34*e37+0.5*e363+0.5*e36*e382+0.5*e36*e372-0.5*e36*e352-0.5*e36*e312-0.5*e36*e322-0.5*e36*e342;
      A[3 + 10*0]=0.5*e01*e002+0.5*e013+0.5*e01*e022+e04*e00*e03+0.5*e01*e042+e04*e02*e05+e07*e00*e06+0.5*e01*e072+e07*e02*e08-0.5*e01*e032-0.5*e01*e052-0.5*e01*e062-0.5*e01*e082;
      A[3 + 10*1]=1.5*e11*e012+0.5*e11*e002+0.5*e11*e022+0.5*e11*e042+0.5*e11*e072-0.5*e11*e032-0.5*e11*e052-0.5*e11*e062-0.5*e11*e082+e01*e10*e00+e01*e12*e02+e04*e10*e03+e04*e00*e13+e04*e01*e14+e04*e12*e05+e04*e02*e15+e14*e00*e03+e14*e02*e05+e07*e10*e06+e07*e00*e16+e07*e01*e17+e07*e12*e08+e07*e02*e18+e17*e00*e06+e17*e02*e08-e01*e13*e03-e01*e16*e06-e01*e15*e05-e01*e18*e08;
      A[3 + 10*2]=e17*e02*e18+e14*e10*e03+e11*e12*e02-e11*e18*e08+0.5*e01*e102+0.5*e01*e122+1.5*e01*e112+0.5*e01*e142+0.5*e01*e172-0.5*e01*e132-0.5*e01*e152-0.5*e01*e162-0.5*e01*e182+e11*e10*e00+e04*e10*e13+e04*e12*e15+e04*e11*e14+e14*e00*e13+e14*e12*e05+e14*e02*e15+e07*e10*e16+e07*e12*e18+e07*e11*e17+e17*e10*e06+e17*e00*e16+e17*e12*e08-e11*e13*e03-e11*e16*e06-e11*e15*e05;
      A[3 + 10*3]=0.5*e11*e102+0.5*e11*e122+0.5*e113+e14*e10*e13+e14*e12*e15+0.5*e11*e142+e17*e10*e16+e17*e12*e18+0.5*e11*e172-0.5*e11*e132-0.5*e11*e152-0.5*e11*e162-0.5*e11*e182;
      A[3 + 10*4]=-e01*e25*e05-e01*e26*e06-e01*e23*e03+e27*e02*e08+e27*e00*e06+e07*e02*e28+e07*e22*e08+e07*e01*e27+e07*e00*e26+e24*e02*e05+e24*e00*e03+e04*e02*e25+e04*e22*e05+e04*e01*e24+e04*e00*e23+e04*e20*e03+e01*e22*e02+e01*e20*e00-e01*e28*e08+e07*e20*e06+0.5*e21*e072+0.5*e21*e042+0.5*e21*e022+0.5*e21*e002+1.5*e21*e012-0.5*e21*e082-0.5*e21*e052-0.5*e21*e062-0.5*e21*e032;
      A[3 + 10*5]=e11*e20*e00+e07*e20*e16+3*e01*e21*e11+e01*e22*e12-e21*e18*e08-e21*e15*e05-e21*e16*e06-e21*e13*e03-e11*e28*e08-e11*e25*e05-e11*e26*e06-e11*e23*e03-e01*e28*e18-e01*e23*e13-e01*e25*e15-e01*e26*e16+e27*e02*e18+e27*e12*e08+e27*e00*e16+e27*e10*e06+e17*e02*e28+e17*e22*e08+e17*e01*e27+e17*e00*e26+e17*e20*e06+e07*e11*e27+e07*e21*e17+e07*e12*e28+e07*e22*e18+e07*e10*e26+e24*e02*e15+e24*e12*e05+e24*e00*e13+e24*e10*e03+e14*e02*e25+e14*e22*e05+e14*e01*e24+e14*e00*e23+e14*e20*e03+e04*e11*e24+e04*e21*e14+e04*e12*e25+e04*e22*e15+e21*e12*e02+e04*e20*e13+e01*e20*e10+e11*e22*e02+e21*e10*e00+e04*e10*e23;
      A[3 + 10*6]=1.5*e21*e112+0.5*e21*e102+0.5*e21*e122+e11*e20*e10+e11*e22*e12+e14*e10*e23+e14*e22*e15+e14*e12*e25-0.5*e21*e162-0.5*e21*e152-0.5*e21*e132-0.5*e21*e182+e27*e12*e18-e11*e26*e16-e11*e25*e15-e11*e23*e13-e11*e28*e18+e17*e20*e16+e17*e10*e26+e17*e22*e18+e17*e12*e28+e17*e11*e27+e27*e10*e16+0.5*e21*e172+e14*e11*e24+e24*e10*e13+e24*e12*e15+0.5*e21*e142+e14*e20*e13;
      A[3 + 10*7]=-0.5*e01*e262-0.5*e01*e282-0.5*e01*e252-0.5*e01*e232+0.5*e01*e272+e27*e22*e08+e27*e02*e28-e21*e23*e03-e21*e26*e06-e21*e25*e05-e21*e28*e08+e04*e22*e25+e24*e20*e03+e24*e00*e23+e24*e22*e05+e24*e02*e25+e07*e20*e26+e07*e21*e27+e07*e22*e28+e27*e20*e06+e27*e00*e26+e21*e20*e00+e21*e22*e02+e04*e20*e23+e04*e21*e24+0.5*e01*e222+0.5*e01*e242+1.5*e01*e212+0.5*e01*e202;
      A[3 + 10*8]=-0.5*e11*e282-0.5*e11*e252-e21*e26*e16+e27*e12*e28-e21*e25*e15-e21*e23*e13-e21*e28*e18+e17*e20*e26+e17*e21*e27+e17*e22*e28+e27*e20*e16+e27*e10*e26+e27*e22*e18+0.5*e11*e242+0.5*e11*e272-0.5*e11*e232-0.5*e11*e262+0.5*e11*e202+1.5*e11*e212+0.5*e11*e222+e21*e20*e10+e14*e20*e23+e14*e21*e24+e14*e22*e25+e24*e20*e13+e24*e10*e23+e24*e22*e15+e24*e12*e25+e21*e22*e12;
      A[3 + 10*9]=0.5*e21*e202+0.5*e213+0.5*e21*e222+e24*e20*e23+0.5*e21*e242+e24*e22*e25+e27*e20*e26+0.5*e21*e272+e27*e22*e28-0.5*e21*e232-0.5*e21*e262-0.5*e21*e282-0.5*e21*e252;
      A[3 + 10*10]=-0.5*e31*e032-0.5*e31*e052-0.5*e31*e062-0.5*e31*e082+e07*e30*e06+e07*e00*e36+e07*e01*e37+e07*e32*e08+e07*e02*e38+e37*e00*e06+e37*e02*e08-e01*e33*e03-e01*e36*e06-e01*e35*e05-e01*e38*e08+0.5*e31*e072+e04*e30*e03+e04*e00*e33+e04*e01*e34+e04*e32*e05+e04*e02*e35+e34*e00*e03+e34*e02*e05+0.5*e31*e002+0.5*e31*e022+0.5*e31*e042+e01*e30*e00+e01*e32*e02+1.5*e31*e012;
      A[3 + 10*11]=e34*e12*e05+e34*e02*e15+e07*e10*e36+e07*e32*e18+e07*e12*e38+e07*e31*e17+e07*e11*e37+e17*e30*e06+e17*e00*e36+e17*e01*e37+e17*e32*e08+e17*e02*e38+e37*e10*e06+e37*e00*e16+e37*e12*e08+e37*e02*e18-e01*e36*e16-e01*e35*e15-e01*e33*e13-e01*e38*e18-e11*e33*e03-e11*e36*e06-e11*e35*e05+e01*e30*e10+e01*e32*e12+3*e01*e31*e11+e11*e30*e00+e11*e32*e02+e31*e10*e00+e31*e12*e02+e04*e30*e13+e04*e10*e33+e04*e32*e15+e04*e12*e35+e04*e31*e14+e04*e11*e34+e14*e30*e03+e14*e00*e33+e14*e01*e34+e14*e32*e05+e14*e02*e35+e34*e10*e03+e34*e00*e13+e07*e30*e16-e11*e38*e08-e31*e13*e03-e31*e16*e06-e31*e15*e05-e31*e18*e08;
      A[3 + 10*12]=-e11*e33*e13-e11*e38*e18+0.5*e31*e142+0.5*e31*e172-0.5*e31*e162-0.5*e31*e152-0.5*e31*e132-0.5*e31*e182+0.5*e31*e122+0.5*e31*e102+e11*e30*e10+e11*e32*e12+e14*e30*e13+e14*e10*e33+e14*e32*e15+e14*e12*e35+e14*e11*e34+e34*e10*e13+e34*e12*e15+e17*e30*e16+e17*e10*e36+e17*e32*e18+e17*e12*e38+e17*e11*e37+e37*e10*e16+e37*e12*e18-e11*e36*e16-e11*e35*e15+1.5*e31*e112;
      A[3 + 10*13]=-e21*e35*e05+e07*e32*e28+e01*e30*e20-e21*e33*e03-e21*e36*e06-e21*e38*e08-e31*e23*e03-e31*e26*e06-e31*e25*e05-e31*e28*e08+3*e01*e31*e21+e01*e32*e22+e21*e30*e00+e21*e32*e02+e31*e20*e00+e31*e22*e02+e04*e30*e23+e04*e20*e33+e04*e31*e24+e04*e21*e34+e04*e32*e25+e04*e22*e35+e24*e30*e03+e24*e00*e33+e24*e01*e34+e24*e32*e05+e24*e02*e35+e34*e20*e03+e34*e00*e23+e34*e22*e05+e34*e02*e25+e07*e30*e26+e07*e20*e36+e07*e31*e27+e07*e21*e37+e07*e22*e38+e27*e30*e06+e27*e00*e36+e27*e01*e37+e27*e32*e08+e27*e02*e38+e37*e00*e26+e37*e22*e08+e37*e02*e28-e01*e33*e23-e01*e36*e26-e01*e38*e28-e01*e35*e25+e37*e20*e06;
      A[3 + 10*14]=e11*e32*e22+e34*e12*e25+e11*e30*e20+3*e11*e31*e21+e21*e30*e10+e21*e32*e12+e34*e10*e23+e34*e22*e15+e17*e30*e26+e17*e20*e36+e17*e31*e27+e17*e21*e37+e17*e32*e28+e17*e22*e38+e27*e30*e16+e27*e10*e36+e27*e32*e18+e27*e12*e38+e27*e11*e37+e37*e20*e16+e37*e10*e26+e37*e22*e18+e37*e12*e28-e11*e33*e23-e11*e36*e26-e11*e38*e28-e11*e35*e25-e21*e36*e16-e21*e35*e15-e21*e33*e13-e21*e38*e18-e31*e26*e16-e31*e25*e15-e31*e23*e13-e31*e28*e18+e31*e20*e10+e31*e22*e12+e14*e30*e23+e14*e20*e33+e14*e31*e24+e14*e21*e34+e14*e32*e25+e14*e22*e35+e24*e30*e13+e24*e10*e33+e24*e32*e15+e24*e12*e35+e24*e11*e34+e34*e20*e13;
      A[3 + 10*15]=-e21*e36*e26+e37*e22*e28-e21*e33*e23-e21*e38*e28-e21*e35*e25+0.5*e31*e222+0.5*e31*e242+0.5*e31*e272-0.5*e31*e232-0.5*e31*e262-0.5*e31*e282-0.5*e31*e252+e21*e30*e20+e21*e32*e22+e24*e30*e23+e24*e20*e33+e24*e21*e34+e24*e32*e25+e24*e22*e35+e34*e20*e23+e34*e22*e25+e27*e30*e26+e27*e20*e36+e27*e21*e37+e27*e32*e28+e27*e22*e38+e37*e20*e26+1.5*e31*e212+0.5*e31*e202;
      A[3 + 10*16]=e04*e32*e35+0.5*e01*e372-0.5*e01*e352-0.5*e01*e362-0.5*e01*e332-0.5*e01*e382+e04*e31*e34+e34*e30*e03+e34*e00*e33+e34*e32*e05+e34*e02*e35+e07*e30*e36+e07*e32*e38+e07*e31*e37+e37*e30*e06+e37*e00*e36+e37*e32*e08+e04*e30*e33+e37*e02*e38-e31*e33*e03-e31*e36*e06-e31*e35*e05-e31*e38*e08+0.5*e01*e302+0.5*e01*e322+1.5*e01*e312+0.5*e01*e342+e31*e30*e00+e31*e32*e02;
      A[3 + 10*17]=e31*e32*e12+e14*e30*e33+e14*e32*e35+e14*e31*e34+e34*e30*e13+e34*e10*e33+e34*e32*e15+e34*e12*e35+e17*e30*e36+e17*e32*e38+e17*e31*e37+e37*e30*e16+e37*e10*e36+e37*e32*e18+e37*e12*e38-e31*e36*e16-e31*e35*e15+0.5*e11*e302+0.5*e11*e322+1.5*e11*e312-e31*e33*e13-e31*e38*e18+0.5*e11*e342+0.5*e11*e372+e31*e30*e10-0.5*e11*e352-0.5*e11*e362-0.5*e11*e332-0.5*e11*e382;
      A[3 + 10*18]=e34*e32*e25+0.5*e21*e342+0.5*e21*e372-0.5*e21*e352-0.5*e21*e362-0.5*e21*e332-0.5*e21*e382+0.5*e21*e302+0.5*e21*e322+1.5*e21*e312+e31*e30*e20+e31*e32*e22+e24*e30*e33+e24*e32*e35+e24*e31*e34+e34*e30*e23+e34*e20*e33+e34*e22*e35+e27*e30*e36+e27*e32*e38+e27*e31*e37+e37*e30*e26+e37*e20*e36+e37*e32*e28+e37*e22*e38-e31*e33*e23-e31*e36*e26-e31*e38*e28-e31*e35*e25;
      A[3 + 10*19]=0.5*e31*e302+0.5*e31*e322+0.5*e313+e34*e30*e33+e34*e32*e35+0.5*e31*e342+e37*e30*e36+e37*e32*e38+0.5*e31*e372-0.5*e31*e352-0.5*e31*e362-0.5*e31*e332-0.5*e31*e382;
      A[4 + 10*0]=e01*e00*e03+0.5*e012*e04+e01*e02*e05+0.5*e04*e032+0.5*e043+0.5*e04*e052+e07*e03*e06+0.5*e04*e072+e07*e05*e08-0.5*e04*e002-0.5*e04*e022-0.5*e04*e062-0.5*e04*e082;
      A[4 + 10*1]=e07*e13*e06+e01*e10*e03-0.5*e14*e002-0.5*e14*e022-0.5*e14*e062-0.5*e14*e082+e01*e00*e13+e01*e11*e04+e01*e12*e05+e01*e02*e15+e11*e00*e03+e11*e02*e05+e04*e13*e03+e04*e15*e05+e07*e03*e16+e07*e04*e17+e07*e15*e08+e07*e05*e18+e17*e03*e06+e17*e05*e08-e04*e10*e00-e04*e12*e02-e04*e16*e06-e04*e18*e08+0.5*e012*e14+1.5*e14*e042+0.5*e14*e032+0.5*e14*e052+0.5*e14*e072;
      A[4 + 10*2]=e11*e10*e03+0.5*e112*e04+0.5*e04*e132+0.5*e04*e152+1.5*e04*e142+0.5*e04*e172-0.5*e04*e102-0.5*e04*e162-0.5*e04*e122-0.5*e04*e182+e01*e10*e13+e01*e12*e15+e01*e11*e14+e11*e00*e13+e11*e12*e05+e11*e02*e15+e14*e13*e03+e14*e15*e05+e07*e13*e16+e07*e15*e18+e07*e14*e17+e17*e13*e06+e17*e03*e16+e17*e15*e08+e17*e05*e18-e14*e10*e00-e14*e12*e02-e14*e16*e06-e14*e18*e08;
      A[4 + 10*3]=e11*e10*e13+e11*e12*e15+0.5*e112*e14+0.5*e14*e132+0.5*e14*e152+0.5*e143+e17*e13*e16+e17*e15*e18+0.5*e14*e172-0.5*e14*e102-0.5*e14*e162-0.5*e14*e122-0.5*e14*e182;
      A[4 + 10*4]=-e04*e28*e08-e04*e26*e06-e04*e22*e02-e04*e20*e00+e27*e05*e08+e27*e03*e06+e07*e05*e28+e07*e25*e08+e07*e04*e27+e07*e03*e26+e07*e23*e06+e04*e25*e05+e04*e23*e03+e21*e02*e05+e21*e00*e03+e01*e02*e25+e01*e22*e05+e01*e21*e04+e01*e00*e23+e01*e20*e03+0.5*e012*e24+0.5*e24*e072+0.5*e24*e052+0.5*e24*e032+1.5*e24*e042-0.5*e24*e022-0.5*e24*e002-0.5*e24*e082-0.5*e24*e062;
      A[4 + 10*5]=e11*e02*e25+e11*e22*e05+e11*e21*e04-e24*e18*e08-e24*e16*e06-e24*e12*e02-e14*e28*e08-e14*e26*e06-e14*e22*e02-e14*e20*e00-e04*e28*e18-e04*e22*e12-e04*e26*e16-e04*e20*e10+e27*e05*e18+e27*e15*e08+e27*e03*e16+e27*e13*e06+e17*e05*e28+e17*e25*e08+e17*e04*e27+e17*e03*e26+e17*e23*e06+e07*e14*e27+e07*e24*e17+e07*e15*e28+e07*e25*e18+e07*e13*e26+e07*e23*e16+e24*e15*e05+e24*e13*e03+e14*e25*e05+e14*e23*e03+3*e04*e24*e14+e04*e25*e15+e04*e23*e13+e21*e02*e15+e21*e12*e05+e21*e00*e13+e21*e10*e03-e24*e10*e00+e01*e20*e13+e01*e10*e23+e01*e22*e15+e01*e12*e25+e01*e11*e24+e11*e20*e03+e11*e00*e23+e01*e21*e14;
      A[4 + 10*6]=e11*e12*e25-0.5*e24*e182-0.5*e24*e102-0.5*e24*e162-0.5*e24*e122+e27*e13*e16+e27*e15*e18-e14*e20*e10-e14*e26*e16-e14*e22*e12-e14*e28*e18+e17*e15*e28+e17*e14*e27+1.5*e24*e142+0.5*e24*e132+0.5*e24*e152+0.5*e112*e24+0.5*e24*e172+e11*e21*e14+e11*e22*e15+e11*e10*e23+e11*e20*e13+e21*e10*e13+e21*e12*e15+e17*e13*e26+e17*e23*e16+e14*e25*e15+e14*e23*e13+e17*e25*e18;
      A[4 + 10*7]=e27*e03*e26+e27*e25*e08+e27*e05*e28-e24*e20*e00-e24*e22*e02-e24*e26*e06-e24*e28*e08+0.5*e04*e232+1.5*e04*e242+0.5*e04*e252+0.5*e04*e272-0.5*e04*e202-0.5*e04*e222-0.5*e04*e262-0.5*e04*e282+e24*e23*e03+e24*e25*e05+e07*e23*e26+e07*e24*e27+e07*e25*e28+e27*e23*e06+e21*e20*e03+e21*e00*e23+e21*e22*e05+e21*e02*e25+0.5*e212*e04+e01*e20*e23+e01*e21*e24+e01*e22*e25;
      A[4 + 10*8]=-e24*e22*e12-e24*e28*e18+0.5*e14*e272-0.5*e14*e202-0.5*e14*e222-0.5*e14*e262-0.5*e14*e282+e17*e23*e26+e17*e24*e27+e17*e25*e28+e27*e23*e16+e27*e13*e26+e27*e25*e18+e27*e15*e28-e24*e20*e10-e24*e26*e16+0.5*e14*e232+1.5*e14*e242+0.5*e14*e252+e21*e10*e23+e21*e22*e15+e21*e12*e25+e24*e23*e13+e24*e25*e15+e21*e20*e13+0.5*e212*e14+e11*e20*e23+e11*e22*e25+e11*e21*e24;
      A[4 + 10*9]=e21*e20*e23+0.5*e212*e24+e21*e22*e25+0.5*e24*e232+0.5*e243+0.5*e24*e252+e27*e23*e26+0.5*e24*e272+e27*e25*e28-0.5*e24*e202-0.5*e24*e222-0.5*e24*e262-0.5*e24*e282;
      A[4 + 10*10]=-e04*e38*e08-e04*e32*e02-e04*e36*e06-0.5*e34*e002-0.5*e34*e022-0.5*e34*e062-0.5*e34*e082+e37*e03*e06+e37*e05*e08-e04*e30*e00+0.5*e34*e032+0.5*e34*e052+0.5*e34*e072+1.5*e34*e042+e01*e30*e03+e01*e00*e33+e01*e31*e04+e01*e32*e05+e01*e02*e35+e31*e00*e03+e31*e02*e05+e04*e33*e03+e04*e35*e05+e07*e03*e36+e07*e04*e37+e07*e35*e08+e07*e05*e38+0.5*e012*e34+e07*e33*e06;
      A[4 + 10*11]=e07*e13*e36+e01*e12*e35-e04*e30*e10+e17*e04*e37+e17*e35*e08+e17*e05*e38+e37*e13*e06+e37*e03*e16+e37*e15*e08+e37*e05*e18-e04*e36*e16+e17*e33*e06+e04*e33*e13+e04*e35*e15+3*e04*e34*e14+e14*e33*e03+e14*e35*e05+e34*e13*e03+e34*e15*e05+e07*e33*e16+e07*e35*e18+e07*e15*e38+e07*e34*e17+e07*e14*e37+e17*e03*e36+e31*e10*e03+e01*e30*e13+e01*e10*e33+e01*e32*e15+e01*e31*e14+e01*e11*e34+e11*e30*e03+e11*e00*e33+e11*e31*e04+e11*e32*e05+e11*e02*e35+e31*e00*e13+e31*e12*e05+e31*e02*e15-e34*e12*e02-e34*e16*e06-e34*e18*e08-e14*e32*e02-e14*e36*e06-e14*e38*e08-e34*e10*e00-e04*e32*e12-e04*e38*e18-e14*e30*e00;
      A[4 + 10*12]=e11*e32*e15-0.5*e34*e102-0.5*e34*e162-0.5*e34*e122-0.5*e34*e182+e37*e13*e16+0.5*e112*e34+1.5*e34*e142+0.5*e34*e132+0.5*e34*e152+0.5*e34*e172+e11*e30*e13+e11*e10*e33+e11*e12*e35+e11*e31*e14+e31*e10*e13+e31*e12*e15+e14*e33*e13+e14*e35*e15+e17*e33*e16+e17*e13*e36+e17*e35*e18+e17*e15*e38+e17*e14*e37+e37*e15*e18-e14*e30*e10-e14*e36*e16-e14*e32*e12-e14*e38*e18;
      A[4 + 10*13]=e01*e22*e35-e04*e30*e20-e04*e32*e22+e01*e31*e24+e01*e21*e34+e01*e32*e25+e21*e30*e03+e21*e00*e33+e21*e31*e04+e21*e32*e05+e21*e02*e35+e31*e20*e03+e31*e00*e23+e31*e22*e05+e31*e02*e25+e04*e33*e23+3*e04*e34*e24+e04*e35*e25+e24*e33*e03+e37*e05*e28-e04*e36*e26-e04*e38*e28-e24*e30*e00-e24*e32*e02-e24*e36*e06-e24*e38*e08+e24*e35*e05+e34*e23*e03+e34*e25*e05+e07*e33*e26+e07*e23*e36+e07*e34*e27+e07*e24*e37+e07*e35*e28+e07*e25*e38+e27*e33*e06+e27*e03*e36+e27*e04*e37+e27*e35*e08+e27*e05*e38+e37*e23*e06+e37*e03*e26+e37*e25*e08-e34*e20*e00-e34*e22*e02-e34*e26*e06-e34*e28*e08+e01*e30*e23+e01*e20*e33;
      A[4 + 10*14]=e21*e10*e33+e11*e30*e23+e11*e20*e33+e11*e31*e24+e11*e21*e34+e11*e32*e25+e11*e22*e35+e21*e30*e13+e21*e32*e15+e21*e12*e35+e21*e31*e14+e31*e20*e13+e31*e10*e23+e31*e22*e15+e31*e12*e25+e14*e33*e23+3*e14*e34*e24+e14*e35*e25+e24*e33*e13+e24*e35*e15+e34*e23*e13+e34*e25*e15+e17*e33*e26+e17*e23*e36+e17*e34*e27+e17*e24*e37+e17*e35*e28+e17*e25*e38+e27*e33*e16+e27*e13*e36+e27*e35*e18+e27*e15*e38+e27*e14*e37+e37*e23*e16+e37*e13*e26+e37*e25*e18+e37*e15*e28-e34*e28*e18-e34*e22*e12-e14*e32*e22-e14*e36*e26-e14*e38*e28-e24*e30*e10-e24*e36*e16-e24*e32*e12-e24*e38*e18-e34*e20*e10-e34*e26*e16-e14*e30*e20;
      A[4 + 10*15]=-0.5*e34*e202-0.5*e34*e222-0.5*e34*e262-0.5*e34*e282+e37*e25*e28-e24*e32*e22-e24*e36*e26-e24*e38*e28-e24*e30*e20+0.5*e212*e34+1.5*e34*e242+0.5*e34*e232+0.5*e34*e252+0.5*e34*e272+e21*e30*e23+e21*e20*e33+e21*e31*e24+e21*e32*e25+e21*e22*e35+e31*e20*e23+e31*e22*e25+e24*e33*e23+e24*e35*e25+e27*e33*e26+e27*e23*e36+e27*e24*e37+e27*e35*e28+e27*e25*e38+e37*e23*e26;
      A[4 + 10*16]=e37*e33*e06+e01*e30*e33+e01*e31*e34+e31*e30*e03+e31*e02*e35+e34*e33*e03+e34*e35*e05+e07*e33*e36+e07*e35*e38+e07*e34*e37+e37*e03*e36+e37*e35*e08+e37*e05*e38-e34*e32*e02-e34*e36*e06-e34*e38*e08+e31*e32*e05+e31*e00*e33+0.5*e312*e04+0.5*e04*e332+0.5*e04*e352+1.5*e04*e342+0.5*e04*e372+e01*e32*e35-0.5*e04*e302-0.5*e04*e322-0.5*e04*e362-0.5*e04*e382-e34*e30*e00;
      A[4 + 10*17]=0.5*e14*e372-0.5*e14*e302-0.5*e14*e322-0.5*e14*e362-0.5*e14*e382+0.5*e312*e14+0.5*e14*e332+0.5*e14*e352+1.5*e14*e342+e11*e30*e33+e11*e32*e35+e11*e31*e34+e31*e30*e13+e31*e10*e33+e31*e32*e15+e31*e12*e35+e34*e33*e13+e34*e35*e15+e17*e33*e36+e17*e35*e38+e17*e34*e37+e37*e33*e16+e37*e13*e36+e37*e35*e18+e37*e15*e38-e34*e30*e10-e34*e36*e16-e34*e32*e12-e34*e38*e18;
      A[4 + 10*18]=-e34*e32*e22-e34*e36*e26-e34*e38*e28+0.5*e24*e332+0.5*e24*e352+1.5*e24*e342+0.5*e24*e372-0.5*e24*e302-0.5*e24*e322-0.5*e24*e362-0.5*e24*e382+e21*e30*e33+0.5*e312*e24+e21*e32*e35+e21*e31*e34+e31*e30*e23+e31*e20*e33+e31*e32*e25+e31*e22*e35+e34*e33*e23+e34*e35*e25+e27*e33*e36+e27*e35*e38+e27*e34*e37+e37*e33*e26+e37*e23*e36+e37*e35*e28+e37*e25*e38-e34*e30*e20;
      A[4 + 10*19]=e31*e30*e33+e31*e32*e35+0.5*e312*e34+0.5*e34*e332+0.5*e34*e352+0.5*e343+e37*e33*e36+e37*e35*e38+0.5*e34*e372-0.5*e34*e302-0.5*e34*e322-0.5*e34*e362-0.5*e34*e382;
      A[5 + 10*0]=e01*e00*e06+0.5*e012*e07+e01*e02*e08+e04*e03*e06+0.5*e042*e07+e04*e05*e08+0.5*e07*e062+0.5*e073+0.5*e07*e082-0.5*e07*e002-0.5*e07*e022-0.5*e07*e032-0.5*e07*e052;
      A[5 + 10*1]=e04*e13*e06+0.5*e042*e17+1.5*e17*e072+0.5*e17*e062+0.5*e17*e082-0.5*e17*e002-0.5*e17*e022-0.5*e17*e032-0.5*e17*e052+e01*e10*e06+e07*e16*e06+e07*e18*e08-e07*e10*e00-e07*e12*e02-e07*e13*e03-e07*e15*e05+e01*e00*e16+e01*e11*e07+e01*e12*e08+e01*e02*e18+e11*e00*e06+e11*e02*e08+e04*e03*e16+e04*e14*e07+e04*e15*e08+e04*e05*e18+e14*e03*e06+e14*e05*e08+0.5*e012*e17;
      A[5 + 10*2]=-e17*e10*e00+0.5*e112*e07+0.5*e142*e07+0.5*e07*e162+0.5*e07*e182+1.5*e07*e172-0.5*e07*e102-0.5*e07*e152-0.5*e07*e132-0.5*e07*e122+e01*e10*e16+e01*e12*e18+e01*e11*e17+e11*e10*e06+e11*e00*e16+e11*e12*e08+e11*e02*e18+e04*e13*e16+e04*e15*e18+e04*e14*e17+e14*e13*e06+e14*e03*e16+e14*e15*e08+e14*e05*e18+e17*e16*e06+e17*e18*e08-e17*e12*e02-e17*e13*e03-e17*e15*e05;
      A[5 + 10*3]=e11*e10*e16+e11*e12*e18+0.5*e112*e17+e14*e13*e16+e14*e15*e18+0.5*e142*e17+0.5*e17*e162+0.5*e17*e182+0.5*e173-0.5*e17*e102-0.5*e17*e152-0.5*e17*e132-0.5*e17*e122;
      A[5 + 10*4]=e01*e22*e08+e07*e28*e08-e07*e20*e00-e07*e23*e03-e07*e22*e02-e07*e25*e05+0.5*e012*e27+0.5*e042*e27+1.5*e27*e072+0.5*e27*e062+0.5*e27*e082-0.5*e27*e002-0.5*e27*e022-0.5*e27*e032-0.5*e27*e052+e07*e26*e06+e01*e20*e06+e01*e00*e26+e01*e21*e07+e01*e02*e28+e21*e00*e06+e21*e02*e08+e04*e23*e06+e04*e03*e26+e04*e24*e07+e04*e25*e08+e04*e05*e28+e24*e03*e06+e24*e05*e08;
      A[5 + 10*5]=e14*e24*e07+e14*e03*e26+e14*e23*e06+e04*e14*e27+e04*e24*e17+e04*e15*e28+e04*e25*e18+e04*e13*e26+e04*e23*e16+e21*e02*e18+e21*e12*e08-e27*e15*e05-e27*e13*e03-e27*e12*e02-e27*e10*e00-e17*e25*e05-e17*e23*e03-e17*e22*e02-e17*e20*e00-e07*e22*e12-e07*e23*e13-e07*e25*e15-e07*e20*e10+e27*e18*e08+e27*e16*e06+e17*e28*e08+e17*e26*e06+3*e07*e27*e17+e07*e28*e18+e07*e26*e16+e24*e05*e18+e24*e15*e08+e24*e03*e16+e24*e13*e06+e14*e05*e28+e14*e25*e08+e01*e12*e28+e01*e20*e16+e01*e10*e26+e01*e22*e18+e01*e21*e17+e11*e20*e06+e01*e11*e27+e21*e00*e16+e21*e10*e06+e11*e21*e07+e11*e22*e08+e11*e02*e28+e11*e00*e26;
      A[5 + 10*6]=-0.5*e27*e102-0.5*e27*e152-0.5*e27*e132-0.5*e27*e122+0.5*e142*e27+1.5*e27*e172+0.5*e27*e162+0.5*e27*e182+0.5*e112*e27+e11*e22*e18+e11*e10*e26+e11*e20*e16-e17*e22*e12-e17*e23*e13-e17*e25*e15-e17*e20*e10+e17*e28*e18+e17*e26*e16+e24*e15*e18+e24*e13*e16+e14*e24*e17+e14*e15*e28+e14*e25*e18+e14*e13*e26+e14*e23*e16+e21*e12*e18+e21*e10*e16+e11*e21*e17+e11*e12*e28;
      A[5 + 10*7]=-0.5*e07*e252+e27*e26*e06+e27*e28*e08-e27*e20*e00-e27*e22*e02-e27*e23*e03-e27*e25*e05+1.5*e07*e272+0.5*e07*e282+e01*e22*e28+e21*e20*e06+e21*e00*e26+e21*e22*e08+e21*e02*e28+e04*e23*e26+e04*e24*e27+e04*e25*e28+e24*e23*e06+e24*e03*e26+e24*e25*e08+e24*e05*e28+0.5*e212*e07+0.5*e242*e07+0.5*e07*e262+e01*e20*e26+e01*e21*e27-0.5*e07*e202-0.5*e07*e232-0.5*e07*e222;
      A[5 + 10*8]=-e27*e25*e15-e27*e23*e13-e27*e22*e12-0.5*e17*e252-0.5*e17*e202-0.5*e17*e222-0.5*e17*e232+0.5*e17*e262+1.5*e17*e272+0.5*e17*e282+e24*e23*e16+e24*e13*e26+e24*e25*e18+e24*e15*e28+e27*e26*e16+e27*e28*e18-e27*e20*e10+e14*e24*e27+e14*e25*e28+0.5*e212*e17+0.5*e242*e17+e11*e20*e26+e11*e21*e27+e11*e22*e28+e21*e20*e16+e21*e10*e26+e21*e22*e18+e21*e12*e28+e14*e23*e26;
      A[5 + 10*9]=e21*e20*e26+0.5*e212*e27+e21*e22*e28+e24*e23*e26+0.5*e242*e27+e24*e25*e28+0.5*e27*e262+0.5*e273+0.5*e27*e282-0.5*e27*e202-0.5*e27*e222-0.5*e27*e232-0.5*e27*e252;
      A[5 + 10*10]=e04*e05*e38+e01*e30*e06-0.5*e37*e002-0.5*e37*e022-0.5*e37*e032-0.5*e37*e052-e07*e32*e02-e07*e35*e05-e07*e33*e03+e07*e36*e06+e07*e38*e08-e07*e30*e00+1.5*e37*e072+0.5*e37*e062+0.5*e37*e082+e01*e02*e38+e31*e00*e06+e31*e02*e08+e04*e33*e06+e04*e03*e36+e04*e34*e07+e04*e35*e08+e34*e03*e06+e34*e05*e08+0.5*e012*e37+0.5*e042*e37+e01*e00*e36+e01*e31*e07+e01*e32*e08;
      A[5 + 10*11]=e14*e33*e06+e11*e30*e06+e11*e00*e36+e11*e31*e07+e31*e10*e06+e11*e32*e08+e11*e02*e38+e31*e00*e16+e31*e12*e08+e31*e02*e18+e04*e33*e16+e04*e13*e36+e04*e35*e18+e04*e15*e38+e01*e10*e36+e01*e32*e18+e01*e12*e38+e01*e31*e17+e01*e11*e37+e01*e30*e16-e17*e35*e05-e37*e10*e00-e37*e12*e02-e37*e13*e03-e37*e15*e05+e37*e18*e08-e07*e30*e10-e07*e35*e15-e07*e33*e13-e07*e32*e12-e17*e30*e00-e17*e32*e02-e17*e33*e03+e07*e38*e18+3*e07*e37*e17+e17*e36*e06+e17*e38*e08+e37*e16*e06+e04*e34*e17+e04*e14*e37+e14*e03*e36+e14*e34*e07+e14*e35*e08+e14*e05*e38+e34*e13*e06+e34*e03*e16+e34*e15*e08+e34*e05*e18+e07*e36*e16;
      A[5 + 10*12]=e11*e32*e18-0.5*e37*e102-0.5*e37*e152-0.5*e37*e132-0.5*e37*e122+0.5*e112*e37+0.5*e142*e37+1.5*e37*e172+0.5*e37*e162+0.5*e37*e182+e11*e10*e36+e11*e12*e38+e11*e31*e17+e31*e10*e16+e31*e12*e18+e14*e33*e16+e14*e13*e36+e14*e35*e18+e14*e15*e38+e14*e34*e17+e34*e13*e16+e34*e15*e18+e17*e36*e16+e17*e38*e18-e17*e30*e10-e17*e35*e15-e17*e33*e13-e17*e32*e12+e11*e30*e16;
      A[5 + 10*13]=e01*e20*e36+e01*e31*e27+e01*e21*e37+e01*e32*e28+e01*e22*e38+e21*e30*e06+e21*e00*e36+e21*e31*e07+e21*e32*e08+e21*e02*e38+e01*e30*e26+e31*e20*e06+e31*e00*e26+e31*e22*e08+e31*e02*e28+e04*e33*e26+e04*e23*e36+e04*e34*e27+e04*e24*e37+e04*e35*e28+e04*e25*e38+e24*e33*e06+e24*e03*e36+e24*e34*e07+e24*e35*e08+e24*e05*e38+e34*e23*e06+e34*e03*e26+e34*e25*e08+e34*e05*e28+e07*e36*e26+3*e07*e37*e27+e07*e38*e28+e27*e36*e06+e27*e38*e08+e37*e26*e06+e37*e28*e08-e07*e30*e20-e07*e32*e22-e07*e33*e23-e07*e35*e25-e27*e30*e00-e27*e32*e02-e27*e33*e03-e27*e35*e05-e37*e20*e00-e37*e22*e02-e37*e23*e03-e37*e25*e05;
      A[5 + 10*14]=e11*e30*e26+e11*e20*e36+e11*e31*e27+e11*e21*e37+e11*e32*e28+e11*e22*e38+e21*e10*e36+e21*e32*e18+e21*e12*e38+e21*e31*e17+e31*e20*e16+e31*e10*e26+e31*e22*e18+e31*e12*e28+e14*e33*e26+e14*e23*e36+e14*e34*e27+e14*e24*e37+e14*e35*e28+e14*e25*e38+e24*e33*e16+e24*e13*e36+e24*e35*e18+e24*e15*e38+e24*e34*e17+e34*e23*e16+e34*e13*e26+e34*e25*e18+e34*e15*e28+e17*e36*e26+3*e17*e37*e27+e17*e38*e28+e27*e36*e16+e27*e38*e18+e37*e26*e16+e37*e28*e18-e17*e30*e20-e17*e32*e22-e17*e33*e23-e17*e35*e25-e27*e30*e10-e27*e35*e15-e27*e33*e13-e27*e32*e12-e37*e20*e10-e37*e25*e15-e37*e23*e13-e37*e22*e12+e21*e30*e16;
      A[5 + 10*15]=e21*e20*e36+e21*e31*e27+e21*e32*e28+e21*e22*e38+e31*e22*e28+e24*e33*e26+e24*e23*e36+e24*e34*e27+e24*e35*e28+e24*e25*e38+e34*e23*e26+e34*e25*e28+e27*e36*e26+e27*e38*e28-e27*e30*e20-e27*e32*e22-e27*e33*e23-e27*e35*e25+0.5*e242*e37+1.5*e37*e272+0.5*e37*e262+0.5*e37*e282+e31*e20*e26+e21*e30*e26+0.5*e212*e37-0.5*e37*e202-0.5*e37*e222-0.5*e37*e232-0.5*e37*e252;
      A[5 + 10*16]=e01*e30*e36+e01*e32*e38+e01*e31*e37+e31*e30*e06+e31*e00*e36+e31*e32*e08+e31*e02*e38+e04*e33*e36+e04*e35*e38+e04*e34*e37+e34*e33*e06+e34*e03*e36+e34*e35*e08+e34*e05*e38+e37*e36*e06+e37*e38*e08-e37*e30*e00-e37*e32*e02-e37*e33*e03-e37*e35*e05+0.5*e312*e07+0.5*e342*e07+0.5*e07*e362+0.5*e07*e382+1.5*e07*e372-0.5*e07*e302-0.5*e07*e352-0.5*e07*e322-0.5*e07*e332;
      A[5 + 10*17]=0.5*e312*e17+0.5*e342*e17+0.5*e17*e362+0.5*e17*e382+1.5*e17*e372-0.5*e17*e302-0.5*e17*e352-0.5*e17*e322-0.5*e17*e332-e37*e32*e12-e37*e33*e13+e11*e30*e36+e11*e32*e38+e11*e31*e37+e31*e30*e16+e31*e10*e36+e31*e32*e18+e31*e12*e38+e14*e33*e36+e14*e35*e38+e14*e34*e37+e34*e33*e16+e34*e13*e36+e34*e35*e18+e34*e15*e38+e37*e36*e16+e37*e38*e18-e37*e30*e10-e37*e35*e15;
      A[5 + 10*18]=e21*e31*e37-0.5*e27*e332+e21*e30*e36+e21*e32*e38+e31*e30*e26+e31*e20*e36+e31*e32*e28+e31*e22*e38+e24*e33*e36+e24*e35*e38+e24*e34*e37+e34*e33*e26+e34*e23*e36+e34*e35*e28+e34*e25*e38+e37*e36*e26+e37*e38*e28-e37*e30*e20-e37*e32*e22-e37*e33*e23-e37*e35*e25+0.5*e312*e27+0.5*e342*e27+0.5*e27*e362+0.5*e27*e382+1.5*e27*e372-0.5*e27*e302-0.5*e27*e352-0.5*e27*e322;
      A[5 + 10*19]=e31*e30*e36+e31*e32*e38+0.5*e312*e37+e34*e33*e36+e34*e35*e38+0.5*e342*e37+0.5*e37*e362+0.5*e37*e382+0.5*e373-0.5*e37*e302-0.5*e37*e352-0.5*e37*e322-0.5*e37*e332;
      A[6 + 10*0]=0.5*e02*e002+0.5*e02*e012+0.5*e023+e05*e00*e03+e05*e01*e04+0.5*e02*e052+e08*e00*e06+e08*e01*e07+0.5*e02*e082-0.5*e02*e032-0.5*e02*e042-0.5*e02*e062-0.5*e02*e072;
      A[6 + 10*1]=-0.5*e12*e042-0.5*e12*e062-0.5*e12*e072+0.5*e12*e082-0.5*e12*e032+1.5*e12*e022+0.5*e12*e002+0.5*e12*e012+0.5*e12*e052+e02*e10*e00+e02*e11*e01+e05*e10*e03+e05*e00*e13+e05*e11*e04+e05*e01*e14+e05*e02*e15+e15*e00*e03+e15*e01*e04+e08*e10*e06+e08*e00*e16+e08*e11*e07+e08*e01*e17+e08*e02*e18+e18*e00*e06+e18*e01*e07-e02*e13*e03-e02*e14*e04-e02*e16*e06-e02*e17*e07;
      A[6 + 10*2]=0.5*e02*e102+1.5*e02*e122+0.5*e02*e112+0.5*e02*e152+0.5*e02*e182-0.5*e02*e162-0.5*e02*e172-0.5*e02*e132-0.5*e02*e142+e12*e10*e00+e12*e11*e01+e05*e10*e13+e05*e12*e15+e05*e11*e14+e15*e10*e03+e15*e00*e13+e15*e11*e04+e15*e01*e14+e08*e10*e16+e08*e12*e18+e08*e11*e17+e18*e10*e06+e18*e00*e16+e18*e11*e07+e18*e01*e17-e12*e13*e03-e12*e14*e04-e12*e16*e06-e12*e17*e07;
      A[6 + 10*3]=0.5*e12*e102+0.5*e123+0.5*e12*e112+e15*e10*e13+0.5*e12*e152+e15*e11*e14+e18*e10*e16+0.5*e12*e182+e18*e11*e17-0.5*e12*e162-0.5*e12*e172-0.5*e12*e132-0.5*e12*e142;
      A[6 + 10*4]=-0.5*e22*e032-0.5*e22*e042-0.5*e22*e062-0.5*e22*e072+0.5*e22*e082+1.5*e22*e022+0.5*e22*e002+0.5*e22*e012+0.5*e22*e052+e02*e20*e00+e02*e21*e01+e05*e20*e03+e05*e00*e23+e05*e21*e04+e05*e01*e24+e05*e02*e25+e25*e00*e03+e25*e01*e04+e08*e20*e06+e08*e00*e26+e08*e21*e07+e08*e01*e27+e08*e02*e28+e28*e00*e06+e28*e01*e07-e02*e27*e07-e02*e23*e03-e02*e24*e04-e02*e26*e06;
      A[6 + 10*5]=-e22*e17*e07-e22*e16*e06-e22*e14*e04-e22*e13*e03-e12*e26*e06-e12*e24*e04-e12*e23*e03-e12*e27*e07-e02*e24*e14-e02*e23*e13-e02*e27*e17-e02*e26*e16+e28*e01*e17+e28*e11*e07+e28*e00*e16+e28*e10*e06+e18*e02*e28+e18*e01*e27+e18*e21*e07+e18*e00*e26+e18*e20*e06+e08*e11*e27+e08*e21*e17+e08*e12*e28+e08*e22*e18+e08*e10*e26+e25*e01*e14+e25*e11*e04+e25*e00*e13+e25*e10*e03+e15*e01*e24+e02*e21*e11+e12*e21*e01+e15*e02*e25+e15*e21*e04+e05*e22*e15+e05*e11*e24+e15*e20*e03+e15*e00*e23+e05*e10*e23+e05*e12*e25+e05*e21*e14+e22*e10*e00+e22*e11*e01+e02*e20*e10+3*e02*e22*e12+e12*e20*e00+e08*e20*e16+e05*e20*e13;
      A[6 + 10*6]=-e12*e24*e14-e12*e23*e13-e12*e27*e17-e12*e26*e16+e28*e11*e17+e28*e10*e16+e18*e11*e27+e18*e21*e17+e18*e12*e28+e18*e10*e26+e18*e20*e16+e25*e11*e14+e25*e10*e13+e15*e11*e24+e15*e21*e14+e15*e12*e25+e15*e10*e23+e15*e20*e13+e12*e21*e11+0.5*e22*e182+0.5*e22*e152+1.5*e22*e122+0.5*e22*e102+e12*e20*e10+0.5*e22*e112-0.5*e22*e172-0.5*e22*e132-0.5*e22*e142-0.5*e22*e162;
      A[6 + 10*7]=0.5*e02*e282+e28*e01*e27-e22*e27*e07-e22*e23*e03-e22*e24*e04-e22*e26*e06+0.5*e02*e252+e05*e20*e23+e05*e22*e25+e25*e20*e03+e25*e00*e23+e25*e21*e04+e25*e01*e24+e08*e20*e26+e08*e21*e27+e08*e22*e28+e28*e20*e06+e28*e00*e26+e28*e21*e07+e05*e21*e24+0.5*e02*e202+0.5*e02*e212+1.5*e02*e222+e22*e20*e00+e22*e21*e01-0.5*e02*e272-0.5*e02*e242-0.5*e02*e232-0.5*e02*e262;
      A[6 + 10*8]=-e22*e27*e17-e22*e23*e13-e22*e24*e14-0.5*e12*e232-0.5*e12*e262-0.5*e12*e242-0.5*e12*e272+0.5*e12*e282+e18*e21*e27+e28*e20*e16+e28*e10*e26+e28*e21*e17+e28*e11*e27-e22*e26*e16+e18*e22*e28+0.5*e12*e252+0.5*e12*e202+0.5*e12*e212+1.5*e12*e222+e22*e20*e10+e15*e20*e23+e15*e21*e24+e15*e22*e25+e25*e20*e13+e25*e10*e23+e25*e21*e14+e25*e11*e24+e18*e20*e26+e22*e21*e11;
      A[6 + 10*9]=0.5*e22*e202+0.5*e22*e212+0.5*e223+e25*e20*e23+e25*e21*e24+0.5*e22*e252+e28*e20*e26+e28*e21*e27+0.5*e22*e282-0.5*e22*e232-0.5*e22*e262-0.5*e22*e242-0.5*e22*e272;
      A[6 + 10*10]=e08*e31*e07-0.5*e32*e032-e02*e33*e03-e02*e34*e04-e02*e36*e06-0.5*e32*e042-0.5*e32*e062-0.5*e32*e072+e38*e01*e07+e38*e00*e06-e02*e37*e07+e05*e31*e04+e05*e01*e34+e05*e02*e35+e35*e01*e04+e35*e00*e03+e08*e30*e06+e08*e00*e36+e08*e01*e37+e08*e02*e38+0.5*e32*e052+e02*e30*e00+e02*e31*e01+e05*e30*e03+e05*e00*e33+1.5*e32*e022+0.5*e32*e012+0.5*e32*e002+0.5*e32*e082;
      A[6 + 10*11]=e05*e32*e15+e32*e11*e01+e38*e10*e06+e08*e12*e38-e32*e14*e04-e32*e16*e06-e32*e17*e07-e12*e36*e06-e32*e13*e03-e02*e34*e14-e12*e37*e07-e12*e33*e03-e12*e34*e04-e02*e37*e17-e02*e33*e13+e38*e01*e17-e02*e36*e16+e18*e01*e37+e18*e02*e38+e38*e00*e16+e38*e11*e07+e08*e30*e16+e08*e10*e36+e08*e32*e18+e08*e31*e17+e08*e11*e37+e18*e30*e06+e18*e00*e36+e18*e31*e07+e35*e10*e03+e35*e00*e13+e35*e11*e04+e35*e01*e14+e15*e02*e35+e05*e10*e33+e05*e12*e35+e05*e31*e14+e05*e11*e34+e15*e30*e03+e15*e00*e33+e15*e31*e04+e15*e01*e34+e05*e30*e13+e02*e30*e10+e02*e31*e11+3*e02*e32*e12+e12*e30*e00+e12*e31*e01+e32*e10*e00;
      A[6 + 10*12]=0.5*e32*e102+0.5*e32*e112+e12*e30*e10+1.5*e32*e122+e12*e31*e11+e15*e30*e13+e15*e10*e33+e15*e12*e35+e15*e31*e14+e15*e11*e34+e35*e10*e13-0.5*e32*e162-0.5*e32*e172-0.5*e32*e132-0.5*e32*e142-e12*e37*e17-e12*e33*e13-e12*e34*e14+0.5*e32*e182+0.5*e32*e152+e35*e11*e14+e18*e30*e16+e18*e10*e36+e18*e12*e38+e18*e31*e17+e18*e11*e37+e38*e10*e16+e38*e11*e17-e12*e36*e16;
      A[6 + 10*13]=3*e02*e32*e22+e05*e31*e24+e08*e22*e38+e02*e31*e21+e22*e30*e00+e22*e31*e01+e32*e20*e00+e32*e21*e01+e05*e30*e23+e05*e20*e33+e05*e21*e34-e22*e37*e07-e22*e33*e03-e22*e34*e04-e22*e36*e06-e32*e27*e07-e32*e23*e03-e32*e24*e04-e32*e26*e06+e05*e32*e25+e25*e30*e03+e25*e00*e33+e25*e31*e04+e25*e01*e34+e25*e02*e35+e35*e20*e03+e35*e00*e23+e35*e21*e04+e35*e01*e24+e08*e30*e26+e08*e20*e36+e08*e31*e27+e08*e21*e37+e08*e32*e28+e28*e30*e06+e28*e00*e36+e28*e31*e07+e28*e01*e37+e28*e02*e38+e38*e20*e06+e38*e00*e26+e38*e21*e07+e38*e01*e27-e02*e33*e23-e02*e36*e26-e02*e34*e24-e02*e37*e27+e05*e22*e35+e02*e30*e20;
      A[6 + 10*14]=e18*e22*e38+e12*e31*e21+3*e12*e32*e22+e22*e30*e10+e22*e31*e11+e32*e20*e10+e32*e21*e11+e15*e30*e23+e15*e20*e33+e15*e31*e24+e15*e21*e34+e15*e32*e25+e15*e22*e35+e25*e30*e13+e25*e10*e33+e25*e12*e35+e25*e31*e14+e25*e11*e34+e35*e20*e13+e35*e10*e23+e35*e21*e14+e35*e11*e24+e18*e30*e26+e18*e20*e36+e18*e31*e27+e18*e21*e37+e18*e32*e28+e28*e30*e16+e28*e10*e36+e28*e12*e38+e28*e31*e17+e28*e11*e37+e38*e20*e16+e38*e10*e26+e12*e30*e20-e22*e37*e17-e22*e33*e13-e22*e34*e14-e32*e26*e16-e32*e27*e17-e32*e23*e13-e32*e24*e14-e22*e36*e16+e38*e21*e17+e38*e11*e27-e12*e33*e23-e12*e36*e26-e12*e34*e24-e12*e37*e27;
      A[6 + 10*15]=e25*e30*e23+e22*e30*e20+e22*e31*e21+e25*e20*e33+e25*e31*e24+e25*e21*e34+e25*e22*e35+e35*e20*e23+e35*e21*e24+e28*e30*e26+e28*e20*e36+e28*e31*e27+e28*e21*e37+e28*e22*e38+e38*e20*e26+e38*e21*e27-e22*e33*e23-e22*e36*e26-e22*e34*e24-e22*e37*e27+0.5*e32*e212+0.5*e32*e252+1.5*e32*e222+0.5*e32*e202+0.5*e32*e282-0.5*e32*e232-0.5*e32*e262-0.5*e32*e242-0.5*e32*e272;
      A[6 + 10*16]=0.5*e02*e302+1.5*e02*e322+0.5*e02*e312+0.5*e02*e352+0.5*e02*e382-0.5*e02*e342-0.5*e02*e362-0.5*e02*e332-0.5*e02*e372+e38*e30*e06+e32*e30*e00+e32*e31*e01+e05*e30*e33+e05*e32*e35+e05*e31*e34+e35*e30*e03+e35*e00*e33+e35*e31*e04+e35*e01*e34+e08*e30*e36+e08*e32*e38+e08*e31*e37+e38*e00*e36+e38*e31*e07+e38*e01*e37-e32*e37*e07-e32*e33*e03-e32*e34*e04-e32*e36*e06;
      A[6 + 10*17]=e32*e30*e10+e32*e31*e11+e15*e30*e33+e15*e32*e35+e15*e31*e34+e35*e30*e13+e35*e10*e33+e35*e31*e14+e35*e11*e34+e18*e30*e36+e18*e32*e38+e18*e31*e37+e38*e30*e16+e38*e10*e36+e38*e31*e17+e38*e11*e37-e32*e36*e16-e32*e37*e17-e32*e33*e13-e32*e34*e14+0.5*e12*e382-0.5*e12*e342-0.5*e12*e362-0.5*e12*e332-0.5*e12*e372+0.5*e12*e352+1.5*e12*e322+0.5*e12*e312+0.5*e12*e302;
      A[6 + 10*18]=0.5*e22*e302+0.5*e22*e312+0.5*e22*e352+0.5*e22*e382-0.5*e22*e342-0.5*e22*e362-0.5*e22*e332-0.5*e22*e372+1.5*e22*e322+e32*e30*e20+e32*e31*e21+e25*e30*e33+e25*e32*e35+e25*e31*e34+e35*e30*e23+e35*e20*e33+e35*e31*e24+e35*e21*e34+e28*e30*e36+e28*e32*e38+e28*e31*e37+e38*e30*e26+e38*e20*e36+e38*e31*e27+e38*e21*e37-e32*e33*e23-e32*e36*e26-e32*e34*e24-e32*e37*e27;
      A[6 + 10*19]=0.5*e32*e302+0.5*e323+0.5*e32*e312+e35*e30*e33+0.5*e32*e352+e35*e31*e34+e38*e30*e36+0.5*e32*e382+e38*e31*e37-0.5*e32*e342-0.5*e32*e362-0.5*e32*e332-0.5*e32*e372;
      A[7 + 10*0]=e02*e01*e04+e02*e00*e03+0.5*e022*e05+0.5*e05*e032+0.5*e05*e042+0.5*e053+e08*e03*e06+e08*e04*e07+0.5*e05*e082-0.5*e05*e002-0.5*e05*e062-0.5*e05*e012-0.5*e05*e072;
      A[7 + 10*1]=e08*e13*e06+e02*e10*e03+e02*e00*e13+e02*e11*e04+e02*e01*e14+e02*e12*e05+e12*e01*e04+e12*e00*e03+e05*e13*e03+e05*e14*e04+e08*e03*e16+e08*e14*e07+e08*e04*e17+e08*e05*e18+e18*e03*e06+e18*e04*e07-e05*e10*e00-e05*e11*e01-e05*e16*e06-e05*e17*e07+0.5*e022*e15+1.5*e15*e052+0.5*e15*e032+0.5*e15*e042+0.5*e15*e082-0.5*e15*e002-0.5*e15*e062-0.5*e15*e012-0.5*e15*e072;
      A[7 + 10*2]=0.5*e122*e05+0.5*e05*e132+1.5*e05*e152+0.5*e05*e142+0.5*e05*e182-0.5*e05*e102-0.5*e05*e162-0.5*e05*e112-0.5*e05*e172+e02*e10*e13+e02*e12*e15+e02*e11*e14+e12*e10*e03+e12*e00*e13+e12*e11*e04+e12*e01*e14+e15*e13*e03+e15*e14*e04+e08*e13*e16+e08*e15*e18+e08*e14*e17+e18*e13*e06+e18*e03*e16+e18*e14*e07+e18*e04*e17-e15*e11*e01-e15*e16*e06-e15*e17*e07-e15*e10*e00;
      A[7 + 10*3]=e12*e10*e13+0.5*e122*e15+e12*e11*e14+0.5*e15*e132+0.5*e153+0.5*e15*e142+e18*e13*e16+0.5*e15*e182+e18*e14*e17-0.5*e15*e102-0.5*e15*e162-0.5*e15*e112-0.5*e15*e172;
      A[7 + 10*4]=0.5*e25*e082-0.5*e25*e002-0.5*e25*e062-0.5*e25*e012-0.5*e25*e072+e02*e20*e03+e02*e00*e23+e02*e21*e04+e02*e01*e24+e02*e22*e05+e22*e01*e04+e22*e00*e03+e05*e23*e03+e05*e24*e04+e08*e23*e06+e08*e03*e26+e08*e24*e07+e08*e04*e27+e08*e05*e28+e28*e03*e06+e28*e04*e07-e05*e20*e00-e05*e27*e07-e05*e21*e01-e05*e26*e06+0.5*e022*e25+1.5*e25*e052+0.5*e25*e032+0.5*e25*e042;
      A[7 + 10*5]=-e25*e17*e07-e25*e16*e06-e25*e11*e01-e25*e10*e00-e15*e26*e06-e15*e21*e01-e15*e27*e07-e15*e20*e00-e05*e27*e17-e05*e21*e11-e05*e26*e16-e05*e20*e10+e28*e04*e17+e28*e14*e07+e28*e03*e16+e28*e13*e06+e18*e05*e28+e18*e04*e27+e18*e24*e07+e18*e03*e26+e18*e23*e06+e08*e14*e27+e08*e24*e17+e08*e15*e28+e08*e25*e18+e08*e13*e26+e08*e23*e16+e25*e14*e04+e25*e13*e03+e15*e24*e04+e15*e23*e03+e05*e24*e14+3*e05*e25*e15+e05*e23*e13+e22*e01*e14+e22*e11*e04+e22*e00*e13+e22*e10*e03+e12*e22*e05+e12*e01*e24+e12*e21*e04+e12*e00*e23+e12*e20*e03+e02*e11*e24+e02*e21*e14+e02*e12*e25+e02*e22*e15+e02*e10*e23+e02*e20*e13;
      A[7 + 10*6]=-e15*e27*e17-e15*e21*e11-e15*e26*e16+e28*e14*e17+e28*e13*e16+e18*e14*e27+e18*e24*e17+e18*e15*e28+e18*e13*e26+e15*e24*e14+e15*e23*e13+e22*e11*e14+e22*e10*e13+e12*e11*e24+e12*e21*e14+e12*e22*e15+e12*e10*e23+e18*e23*e16+0.5*e25*e142+0.5*e25*e182+1.5*e25*e152+0.5*e25*e132+0.5*e122*e25+e12*e20*e13-0.5*e25*e172-0.5*e25*e162-0.5*e25*e112-0.5*e25*e102-e15*e20*e10;
      A[7 + 10*7]=e28*e24*e07-0.5*e05*e272-0.5*e05*e262-0.5*e05*e212+0.5*e05*e282-0.5*e05*e202+e28*e23*e06+e08*e23*e26+e08*e25*e28+e08*e24*e27+e28*e03*e26+e28*e04*e27-e25*e27*e07-e25*e21*e01-e25*e26*e06+e02*e20*e23+e02*e22*e25+e02*e21*e24+e22*e20*e03+e22*e00*e23+e22*e21*e04+e22*e01*e24+e25*e23*e03+e25*e24*e04+0.5*e222*e05+0.5*e05*e232+1.5*e05*e252+0.5*e05*e242-e25*e20*e00;
      A[7 + 10*8]=-0.5*e15*e202-0.5*e15*e262-0.5*e15*e212-0.5*e15*e272+e18*e23*e26+e18*e25*e28+e18*e24*e27+e28*e23*e16+e28*e13*e26+e28*e24*e17+e28*e14*e27-e25*e20*e10-e25*e26*e16-e25*e21*e11-e25*e27*e17+0.5*e15*e282+0.5*e15*e232+1.5*e15*e252+0.5*e15*e242+0.5*e222*e15+e12*e21*e24+e22*e20*e13+e22*e10*e23+e22*e21*e14+e22*e11*e24+e25*e23*e13+e25*e24*e14+e12*e20*e23+e12*e22*e25;
      A[7 + 10*9]=e22*e20*e23+0.5*e222*e25+e22*e21*e24+0.5*e25*e232+0.5*e253+0.5*e25*e242+e28*e23*e26+0.5*e25*e282+e28*e24*e27-0.5*e25*e202-0.5*e25*e262-0.5*e25*e212-0.5*e25*e272;
      A[7 + 10*10]=-0.5*e35*e062-0.5*e35*e012-0.5*e35*e072-e05*e30*e00-e05*e31*e01-e05*e36*e06-e05*e37*e07-0.5*e35*e002+0.5*e35*e082+e05*e34*e04+e08*e33*e06+e08*e03*e36+e08*e34*e07+e08*e04*e37+e08*e05*e38+e38*e04*e07+e38*e03*e06+0.5*e022*e35+1.5*e35*e052+0.5*e35*e042+0.5*e35*e032+e02*e30*e03+e02*e00*e33+e02*e31*e04+e02*e01*e34+e02*e32*e05+e32*e01*e04+e32*e00*e03+e05*e33*e03;
      A[7 + 10*11]=e08*e33*e16-e35*e16*e06-e35*e17*e07-e15*e30*e00-e15*e37*e07-e15*e31*e01-e15*e36*e06-e35*e10*e00-e35*e11*e01-e05*e37*e17-e05*e31*e11+e38*e04*e17-e05*e30*e10-e05*e36*e16+e18*e33*e06+e18*e03*e36+e18*e34*e07+e18*e04*e37+e18*e05*e38+e38*e13*e06+e38*e03*e16+e38*e14*e07+e35*e14*e04+e08*e13*e36+e08*e35*e18+e08*e15*e38+e08*e34*e17+e08*e14*e37+e35*e13*e03+e05*e33*e13+3*e05*e35*e15+e05*e34*e14+e15*e33*e03+e15*e34*e04+e12*e01*e34+e12*e32*e05+e32*e10*e03+e32*e00*e13+e32*e11*e04+e32*e01*e14+e12*e30*e03+e02*e30*e13+e02*e32*e15+e02*e10*e33+e02*e12*e35+e12*e00*e33+e02*e31*e14+e02*e11*e34+e12*e31*e04;
      A[7 + 10*12]=-0.5*e35*e162-0.5*e35*e172-e15*e36*e16-e15*e31*e11-e15*e37*e17-0.5*e35*e102-0.5*e35*e112-e15*e30*e10+e18*e13*e36+e18*e15*e38+e18*e34*e17+e18*e14*e37+e38*e13*e16+e38*e14*e17+e18*e33*e16+1.5*e35*e152+0.5*e35*e132+0.5*e35*e142+0.5*e35*e182+0.5*e122*e35+e32*e10*e13+e32*e11*e14+e15*e33*e13+e15*e34*e14+e12*e10*e33+e12*e32*e15+e12*e31*e14+e12*e11*e34+e12*e30*e13;
      A[7 + 10*13]=e05*e33*e23+3*e05*e35*e25+e05*e34*e24+e25*e33*e03+e25*e34*e04+e35*e23*e03+e35*e24*e04+e08*e33*e26+e08*e23*e36+e08*e35*e28+e02*e20*e33+e02*e32*e25+e02*e22*e35+e02*e31*e24+e02*e21*e34+e22*e30*e03+e22*e00*e33+e22*e31*e04+e22*e01*e34+e22*e32*e05+e32*e20*e03+e32*e00*e23+e32*e21*e04+e32*e01*e24+e02*e30*e23-e35*e27*e07-e35*e21*e01-e35*e26*e06+e08*e25*e38+e08*e34*e27+e08*e24*e37+e28*e33*e06+e28*e03*e36+e28*e34*e07+e28*e04*e37+e28*e05*e38+e38*e23*e06+e38*e03*e26+e38*e24*e07+e38*e04*e27-e05*e30*e20-e05*e36*e26-e05*e31*e21-e05*e37*e27-e25*e30*e00-e25*e37*e07-e25*e31*e01-e25*e36*e06-e35*e20*e00;
      A[7 + 10*14]=e12*e21*e34+e18*e25*e38+e12*e30*e23+e12*e20*e33+e12*e32*e25+e12*e22*e35+e12*e31*e24+e22*e30*e13+e22*e10*e33+e22*e32*e15+e22*e31*e14+e22*e11*e34+e32*e20*e13+e32*e10*e23+e32*e21*e14-e25*e30*e10-e25*e36*e16-e25*e31*e11-e25*e37*e17-e35*e20*e10-e35*e26*e16-e35*e21*e11-e35*e27*e17+e15*e33*e23+3*e15*e35*e25+e15*e34*e24+e25*e33*e13+e25*e34*e14+e35*e23*e13+e35*e24*e14+e18*e33*e26+e18*e23*e36+e18*e35*e28+e18*e34*e27+e18*e24*e37+e28*e33*e16+e28*e13*e36+e28*e15*e38+e28*e34*e17+e28*e14*e37+e38*e23*e16+e38*e13*e26+e38*e24*e17+e38*e14*e27-e15*e30*e20-e15*e36*e26-e15*e31*e21-e15*e37*e27+e32*e11*e24;
      A[7 + 10*15]=-0.5*e35*e202-0.5*e35*e262-0.5*e35*e212-0.5*e35*e272+e25*e34*e24+e28*e23*e36+e28*e25*e38+e28*e34*e27+e28*e24*e37+e38*e23*e26+e38*e24*e27-e25*e30*e20-e25*e36*e26-e25*e31*e21-e25*e37*e27+e25*e33*e23+0.5*e222*e35+1.5*e35*e252+0.5*e35*e232+0.5*e35*e242+0.5*e35*e282+e22*e30*e23+e22*e20*e33+e22*e32*e25+e22*e31*e24+e22*e21*e34+e32*e20*e23+e32*e21*e24+e28*e33*e26;
      A[7 + 10*16]=-e35*e30*e00-e35*e31*e01-e35*e36*e06-e35*e37*e07+0.5*e322*e05+0.5*e05*e332+0.5*e05*e342+1.5*e05*e352+0.5*e05*e382-0.5*e05*e302-0.5*e05*e362-0.5*e05*e312-0.5*e05*e372+e02*e30*e33+e02*e31*e34+e02*e32*e35+e32*e30*e03+e32*e00*e33+e32*e31*e04+e32*e01*e34+e35*e33*e03+e35*e34*e04+e08*e33*e36+e08*e34*e37+e08*e35*e38+e38*e33*e06+e38*e03*e36+e38*e34*e07+e38*e04*e37;
      A[7 + 10*17]=-e35*e30*e10+e12*e32*e35-0.5*e15*e362-0.5*e15*e312-0.5*e15*e372-e35*e36*e16+0.5*e322*e15+0.5*e15*e332+0.5*e15*e342+1.5*e15*e352+0.5*e15*e382-0.5*e15*e302+e12*e30*e33+e12*e31*e34+e32*e30*e13+e32*e10*e33+e32*e31*e14+e32*e11*e34+e35*e33*e13+e35*e34*e14+e18*e33*e36+e18*e34*e37+e18*e35*e38+e38*e33*e16+e38*e13*e36+e38*e34*e17+e38*e14*e37-e35*e31*e11-e35*e37*e17;
      A[7 + 10*18]=-0.5*e25*e302-0.5*e25*e362-0.5*e25*e312-0.5*e25*e372+0.5*e322*e25+0.5*e25*e332+0.5*e25*e342+1.5*e25*e352+0.5*e25*e382+e22*e30*e33+e22*e31*e34+e22*e32*e35+e32*e30*e23+e32*e20*e33+e32*e31*e24+e32*e21*e34+e35*e33*e23+e35*e34*e24+e28*e33*e36+e28*e34*e37+e28*e35*e38+e38*e33*e26+e38*e23*e36+e38*e34*e27+e38*e24*e37-e35*e30*e20-e35*e36*e26-e35*e31*e21-e35*e37*e27;
      A[7 + 10*19]=e32*e30*e33+e32*e31*e34+0.5*e322*e35+0.5*e35*e332+0.5*e35*e342+0.5*e353+e38*e33*e36+e38*e34*e37+0.5*e35*e382-0.5*e35*e302-0.5*e35*e362-0.5*e35*e312-0.5*e35*e372;
      A[8 + 10*0]=e02*e00*e06+e02*e01*e07+0.5*e022*e08+e05*e04*e07+e05*e03*e06+0.5*e052*e08+0.5*e08*e062+0.5*e08*e072+0.5*e083-0.5*e08*e042-0.5*e08*e002-0.5*e08*e012-0.5*e08*e032;
      A[8 + 10*1]=e02*e10*e06+e02*e00*e16+e02*e11*e07+e02*e01*e17+e02*e12*e08+e12*e00*e06+e12*e01*e07+e05*e13*e06+e05*e03*e16+e05*e14*e07+e05*e04*e17+e05*e15*e08+e15*e04*e07+e15*e03*e06+e08*e16*e06+e08*e17*e07-e08*e10*e00-e08*e11*e01-e08*e13*e03-e08*e14*e04+0.5*e022*e18+0.5*e052*e18+1.5*e18*e082+0.5*e18*e062+0.5*e18*e072-0.5*e18*e042-0.5*e18*e002-0.5*e18*e012-0.5*e18*e032;
      A[8 + 10*2]=e12*e01*e17+0.5*e152*e08+0.5*e08*e162+1.5*e08*e182+0.5*e08*e172-0.5*e08*e102-0.5*e08*e112-0.5*e08*e132-0.5*e08*e142+e05*e13*e16+e05*e14*e17+e05*e15*e18+e15*e13*e06+e15*e03*e16+e15*e14*e07+e15*e04*e17+e18*e16*e06+e18*e17*e07-e18*e10*e00-e18*e11*e01-e18*e13*e03-e18*e14*e04+0.5*e122*e08+e02*e10*e16+e02*e12*e18+e02*e11*e17+e12*e10*e06+e12*e00*e16+e12*e11*e07;
      A[8 + 10*3]=e12*e10*e16+0.5*e122*e18+e12*e11*e17+e15*e13*e16+e15*e14*e17+0.5*e152*e18+0.5*e18*e162+0.5*e183+0.5*e18*e172-0.5*e18*e102-0.5*e18*e112-0.5*e18*e132-0.5*e18*e142;
      A[8 + 10*4]=-e08*e20*e00+e08*e27*e07-e08*e21*e01-e08*e23*e03-e08*e24*e04+e02*e20*e06+e02*e00*e26+e02*e21*e07+e02*e01*e27+e02*e22*e08+e22*e00*e06+e22*e01*e07+e05*e23*e06+e05*e03*e26+e05*e24*e07+e05*e04*e27+e05*e25*e08+e25*e04*e07+e25*e03*e06+e08*e26*e06+0.5*e022*e28+0.5*e052*e28+1.5*e28*e082+0.5*e28*e062+0.5*e28*e072-0.5*e28*e042-0.5*e28*e002-0.5*e28*e012-0.5*e28*e032;
      A[8 + 10*5]=e22*e10*e06+e22*e11*e07+e22*e01*e17+e05*e23*e16+e05*e13*e26+e05*e25*e18+e05*e15*e28+e05*e24*e17+e05*e14*e27+e15*e23*e06+e15*e03*e26+e15*e24*e07+e15*e04*e27+e15*e25*e08+e25*e13*e06+e25*e03*e16+e25*e14*e07+e25*e04*e17+e08*e26*e16+3*e08*e28*e18+e08*e27*e17+e18*e26*e06+e18*e27*e07+e22*e00*e16+e28*e16*e06+e28*e17*e07-e08*e20*e10-e08*e21*e11-e08*e23*e13-e08*e24*e14-e18*e20*e00-e18*e21*e01-e18*e23*e03-e18*e24*e04-e28*e10*e00-e28*e11*e01-e28*e13*e03-e28*e14*e04+e02*e20*e16+e02*e10*e26+e02*e22*e18+e02*e12*e28+e02*e21*e17+e02*e11*e27+e12*e20*e06+e12*e00*e26+e12*e21*e07+e12*e01*e27+e12*e22*e08;
      A[8 + 10*6]=-e18*e24*e14-e18*e21*e11-e18*e23*e13-e18*e20*e10+e18*e27*e17+e18*e26*e16+e25*e14*e17+e25*e13*e16+e15*e25*e18+e15*e14*e27+e15*e24*e17+e15*e13*e26+e15*e23*e16+e22*e11*e17+e22*e10*e16+e12*e11*e27+e12*e21*e17+e12*e22*e18+e12*e10*e26+e12*e20*e16+0.5*e28*e162+0.5*e28*e172+1.5*e28*e182+0.5*e152*e28-0.5*e28*e142-0.5*e28*e112-0.5*e28*e132-0.5*e28*e102+0.5*e122*e28;
      A[8 + 10*7]=-e28*e24*e04-e28*e21*e01-e28*e23*e03-e28*e20*e00+e28*e27*e07+e28*e26*e06+e25*e04*e27+e25*e24*e07+e25*e03*e26+e05*e24*e27+e05*e25*e28+e05*e23*e26+e22*e01*e27+e22*e21*e07+e22*e00*e26+e22*e20*e06+e02*e22*e28+e02*e20*e26+e02*e21*e27+0.5*e222*e08-0.5*e08*e242-0.5*e08*e212-0.5*e08*e232-0.5*e08*e202+0.5*e08*e262+0.5*e08*e272+1.5*e08*e282+0.5*e252*e08+e25*e23*e06;
      A[8 + 10*8]=e25*e24*e17+e25*e14*e27+e28*e26*e16+e28*e27*e17-e28*e21*e11-e28*e24*e14+e12*e22*e28+e22*e10*e26+e22*e21*e17+e22*e11*e27+e15*e23*e26+e15*e25*e28+e15*e24*e27+e25*e23*e16+e25*e13*e26+e22*e20*e16+0.5*e222*e18+0.5*e252*e18+0.5*e18*e262+0.5*e18*e272+e12*e20*e26+e12*e21*e27-e28*e20*e10-0.5*e18*e232-0.5*e18*e242-e28*e23*e13-0.5*e18*e212+1.5*e18*e282-0.5*e18*e202;
      A[8 + 10*9]=e22*e20*e26+e22*e21*e27+0.5*e222*e28+e25*e23*e26+0.5*e252*e28+e25*e24*e27+0.5*e28*e262+0.5*e28*e272+0.5*e283-0.5*e28*e202-0.5*e28*e212-0.5*e28*e232-0.5*e28*e242;
      A[8 + 10*10]=-e08*e30*e00-0.5*e38*e042-0.5*e38*e002-0.5*e38*e012-0.5*e38*e032+1.5*e38*e082+0.5*e38*e062+0.5*e38*e072+e32*e01*e07+e05*e33*e06+e05*e03*e36+e05*e34*e07+e05*e04*e37+e05*e35*e08+e35*e04*e07+e35*e03*e06+e08*e36*e06+e08*e37*e07+0.5*e052*e38+e32*e00*e06+e02*e30*e06+e02*e00*e36+e02*e31*e07+e02*e01*e37+e02*e32*e08+0.5*e022*e38-e08*e33*e03-e08*e31*e01-e08*e34*e04;
      A[8 + 10*11]=-e38*e11*e01-e38*e14*e04-e38*e10*e00-e38*e13*e03-e18*e30*e00-e18*e33*e03-e18*e31*e01-e18*e34*e04-e08*e30*e10-e08*e33*e13-e08*e31*e11-e08*e34*e14+3*e08*e38*e18+e08*e37*e17+e18*e36*e06+e18*e37*e07+e38*e16*e06+e38*e17*e07+e15*e35*e08+e35*e13*e06+e35*e03*e16+e35*e14*e07+e35*e04*e17+e08*e36*e16+e05*e35*e18+e05*e15*e38+e15*e33*e06+e15*e03*e36+e15*e34*e07+e15*e04*e37+e05*e14*e37+e12*e30*e06+e12*e31*e07+e12*e01*e37+e12*e00*e36+e12*e32*e08+e32*e10*e06+e32*e00*e16+e32*e11*e07+e32*e01*e17+e05*e33*e16+e05*e13*e36+e05*e34*e17+e02*e30*e16+e02*e10*e36+e02*e32*e18+e02*e12*e38+e02*e31*e17+e02*e11*e37;
      A[8 + 10*12]=e12*e30*e16+e12*e10*e36+e12*e32*e18+e12*e31*e17+e12*e11*e37+e32*e10*e16+e32*e11*e17+e15*e33*e16+e15*e13*e36-0.5*e38*e102-0.5*e38*e112-0.5*e38*e132-0.5*e38*e142+0.5*e38*e162+0.5*e38*e172+e15*e34*e17+e15*e14*e37+e15*e35*e18+e35*e13*e16+e35*e14*e17+e18*e36*e16+e18*e37*e17-e18*e30*e10-e18*e33*e13-e18*e31*e11-e18*e34*e14+0.5*e122*e38+0.5*e152*e38+1.5*e38*e182;
      A[8 + 10*13]=e22*e30*e06-e28*e34*e04+e05*e35*e28+e02*e22*e38+e22*e00*e36+e22*e31*e07+e22*e01*e37+e02*e32*e28+e02*e21*e37-e38*e20*e00-e28*e31*e01-e38*e23*e03-e38*e21*e01-e38*e24*e04-e28*e30*e00-e08*e30*e20-e08*e31*e21-e08*e33*e23-e08*e34*e24-e28*e33*e03+e35*e24*e07+e35*e04*e27+e08*e36*e26+e08*e37*e27+3*e08*e38*e28+e28*e36*e06+e28*e37*e07+e38*e26*e06+e38*e27*e07+e25*e04*e37+e25*e35*e08+e35*e23*e06+e35*e03*e26+e05*e23*e36+e05*e25*e38+e05*e34*e27+e05*e24*e37+e25*e33*e06+e25*e03*e36+e25*e34*e07+e05*e33*e26+e32*e21*e07+e32*e01*e27+e22*e32*e08+e32*e20*e06+e32*e00*e26+e02*e30*e26+e02*e20*e36+e02*e31*e27;
      A[8 + 10*14]=e35*e13*e26-e38*e21*e11-e38*e24*e14+e35*e24*e17+e35*e14*e27+e18*e36*e26+e18*e37*e27+3*e18*e38*e28+e28*e36*e16+e28*e37*e17+e38*e26*e16+e38*e27*e17-e18*e30*e20-e18*e31*e21-e18*e33*e23-e18*e34*e24-e28*e30*e10-e28*e33*e13-e28*e31*e11-e28*e34*e14-e38*e20*e10-e38*e23*e13+e35*e23*e16+e12*e20*e36+e12*e30*e26+e12*e31*e27+e12*e21*e37+e12*e32*e28+e12*e22*e38+e22*e30*e16+e22*e10*e36+e22*e32*e18+e22*e31*e17+e22*e11*e37+e32*e20*e16+e32*e10*e26+e32*e21*e17+e32*e11*e27+e15*e33*e26+e15*e23*e36+e15*e35*e28+e15*e25*e38+e15*e34*e27+e15*e24*e37+e25*e33*e16+e25*e13*e36+e25*e34*e17+e25*e14*e37+e25*e35*e18;
      A[8 + 10*15]=-e28*e30*e20+e22*e30*e26+e22*e20*e36+e22*e31*e27+e22*e21*e37+e22*e32*e28+e32*e20*e26+e32*e21*e27+e25*e33*e26+e25*e23*e36+e25*e35*e28+e25*e34*e27+e25*e24*e37+e35*e23*e26+e35*e24*e27+e28*e36*e26+e28*e37*e27-e28*e31*e21-e28*e33*e23-e28*e34*e24-0.5*e38*e242+0.5*e252*e38+1.5*e38*e282+0.5*e38*e262+0.5*e38*e272-0.5*e38*e202-0.5*e38*e212-0.5*e38*e232+0.5*e222*e38;
      A[8 + 10*16]=-0.5*e08*e312-0.5*e08*e342+0.5*e352*e08+0.5*e08*e362+1.5*e08*e382+0.5*e08*e372-0.5*e08*e302-0.5*e08*e332+e02*e30*e36+e02*e32*e38+e02*e31*e37+e32*e30*e06+e32*e00*e36+e32*e31*e07+e32*e01*e37+e05*e33*e36+e05*e34*e37+e05*e35*e38+e35*e33*e06+e35*e03*e36+e35*e34*e07+e35*e04*e37+0.5*e322*e08+e38*e36*e06+e38*e37*e07-e38*e30*e00-e38*e33*e03-e38*e31*e01-e38*e34*e04;
      A[8 + 10*17]=-e38*e30*e10+e38*e36*e16+e38*e37*e17-e38*e33*e13-e38*e31*e11-e38*e34*e14+0.5*e18*e362+e12*e30*e36+e12*e32*e38+e12*e31*e37+e32*e30*e16+e32*e10*e36+e32*e31*e17+e32*e11*e37+e15*e33*e36+e15*e34*e37+e15*e35*e38+e35*e33*e16+e35*e13*e36+e35*e34*e17+e35*e14*e37+0.5*e322*e18+0.5*e352*e18+1.5*e18*e382+0.5*e18*e372-0.5*e18*e302-0.5*e18*e332-0.5*e18*e312-0.5*e18*e342;
      A[8 + 10*18]=-e38*e30*e20+e25*e35*e38+e22*e30*e36+e22*e32*e38+e22*e31*e37+e32*e30*e26+e32*e20*e36+e32*e31*e27+e32*e21*e37+e25*e33*e36+e25*e34*e37+e35*e33*e26+e35*e23*e36+e35*e34*e27+e35*e24*e37+e38*e36*e26+e38*e37*e27-e38*e31*e21-e38*e33*e23-e38*e34*e24-0.5*e28*e332-0.5*e28*e312-0.5*e28*e342+0.5*e322*e28+0.5*e352*e28+0.5*e28*e362+1.5*e28*e382+0.5*e28*e372-0.5*e28*e302;
      A[8 + 10*19]=e32*e30*e36+0.5*e322*e38+e32*e31*e37+e35*e33*e36+e35*e34*e37+0.5*e352*e38+0.5*e38*e362+0.5*e383+0.5*e38*e372-0.5*e38*e302-0.5*e38*e332-0.5*e38*e312-0.5*e38*e342;
      A[9 + 10*0]=e00*e04*e08-e00*e05*e07+e03*e02*e07-e03*e01*e08-e06*e02*e04+e06*e01*e05;
      A[9 + 10*1]=e06*e01*e15-e16*e02*e04+e16*e01*e05+e03*e02*e17-e13*e01*e08+e06*e11*e05+e13*e02*e07+e00*e04*e18+e00*e14*e08-e00*e05*e17-e10*e05*e07-e00*e15*e07-e06*e12*e04-e06*e02*e14-e03*e01*e18-e03*e11*e08+e10*e04*e08+e03*e12*e07;
      A[9 + 10*2]=-e13*e01*e18-e13*e11*e08+e13*e12*e07+e13*e02*e17+e03*e12*e17-e10*e15*e07+e10*e04*e18+e10*e14*e08-e10*e05*e17-e00*e15*e17+e00*e14*e18+e16*e01*e15+e06*e11*e15-e06*e12*e14-e16*e12*e04-e16*e02*e14+e16*e11*e05-e03*e11*e18;
      A[9 + 10*3]=e10*e14*e18-e10*e15*e17-e13*e11*e18+e13*e12*e17+e16*e11*e15-e16*e12*e14;
      A[9 + 10*4]=-e20*e05*e07+e03*e22*e07+e06*e21*e05+e06*e01*e25-e23*e01*e08+e23*e02*e07+e00*e24*e08-e00*e25*e07-e00*e05*e27+e00*e04*e28-e06*e22*e04-e06*e02*e24-e03*e21*e08-e03*e01*e28-e26*e02*e04+e26*e01*e05+e03*e02*e27+e20*e04*e08;
      A[9 + 10*5]=e23*e12*e07-e26*e02*e14+e16*e21*e05-e23*e11*e08+e10*e24*e08-e20*e05*e17+e26*e11*e05+e26*e01*e15+e10*e04*e28+e00*e24*e18-e00*e15*e27+e03*e22*e17-e13*e01*e28+e23*e02*e17+e16*e01*e25+e20*e04*e18+e06*e11*e25+e13*e02*e27-e23*e01*e18-e20*e15*e07-e10*e25*e07+e13*e22*e07-e06*e22*e14-e26*e12*e04-e03*e11*e28-e03*e21*e18-e16*e22*e04-e16*e02*e24-e06*e12*e24+e06*e21*e15+e00*e14*e28-e00*e25*e17+e20*e14*e08-e13*e21*e08-e10*e05*e27+e03*e12*e27;
      A[9 + 10*6]=-e13*e11*e28+e13*e12*e27+e13*e22*e17+e16*e11*e25+e10*e14*e28-e13*e21*e18-e23*e11*e18+e23*e12*e17+e20*e14*e18-e20*e15*e17+e26*e11*e15-e10*e15*e27-e10*e25*e17-e16*e22*e14-e16*e12*e24+e16*e21*e15-e26*e12*e14+e10*e24*e18;
      A[9 + 10*7]=e26*e21*e05+e26*e01*e25+e20*e04*e28+e20*e24*e08-e20*e25*e07+e23*e22*e07+e03*e22*e27-e03*e21*e28-e26*e22*e04-e20*e05*e27-e00*e25*e27+e06*e21*e25-e06*e22*e24+e00*e24*e28-e26*e02*e24-e23*e21*e08-e23*e01*e28+e23*e02*e27;
      A[9 + 10*8]=-e10*e25*e27+e10*e24*e28-e20*e15*e27-e20*e25*e17+e20*e14*e28+e20*e24*e18+e26*e11*e25+e23*e22*e17-e23*e11*e28+e23*e12*e27-e23*e21*e18-e13*e21*e28+e13*e22*e27-e26*e12*e24+e26*e21*e15-e16*e22*e24+e16*e21*e25-e26*e22*e14;
      A[9 + 10*9]=-e20*e25*e27+e20*e24*e28-e23*e21*e28+e23*e22*e27-e26*e22*e24+e26*e21*e25;
      A[9 + 10*10]=e03*e02*e37-e03*e31*e08-e03*e01*e38+e03*e32*e07-e00*e35*e07+e30*e04*e08+e06*e31*e05-e36*e02*e04+e36*e01*e05-e06*e32*e04-e06*e02*e34+e06*e01*e35+e00*e04*e38-e00*e05*e37+e33*e02*e07-e33*e01*e08-e30*e05*e07+e00*e34*e08;
      A[9 + 10*11]=-e36*e12*e04+e30*e04*e18-e30*e15*e07-e36*e02*e14-e30*e05*e17+e30*e14*e08-e00*e35*e17-e00*e15*e37+e33*e02*e17-e06*e32*e14-e06*e12*e34-e16*e32*e04+e06*e31*e15+e06*e11*e35+e00*e34*e18-e10*e35*e07-e33*e11*e08-e33*e01*e18+e16*e01*e35-e16*e02*e34+e16*e31*e05-e03*e31*e18-e03*e11*e38+e03*e32*e17+e13*e02*e37-e13*e31*e08-e13*e01*e38+e10*e34*e08+e00*e14*e38+e36*e11*e05+e36*e01*e15+e03*e12*e37-e10*e05*e37+e10*e04*e38+e33*e12*e07+e13*e32*e07;
      A[9 + 10*12]=-e36*e12*e14-e30*e15*e17+e13*e32*e17-e13*e31*e18-e33*e11*e18+e33*e12*e17+e10*e14*e38+e30*e14*e18-e13*e11*e38+e13*e12*e37-e10*e35*e17+e10*e34*e18-e16*e12*e34-e16*e32*e14+e16*e11*e35+e16*e31*e15+e36*e11*e15-e10*e15*e37;
      A[9 + 10*13]=-e06*e22*e34-e06*e32*e24-e00*e25*e37-e00*e35*e27+e23*e02*e37+e00*e24*e38-e23*e01*e38-e03*e31*e28-e33*e01*e28+e03*e22*e37+e03*e32*e27+e33*e02*e27-e03*e21*e38-e26*e32*e04-e33*e21*e08+e36*e01*e25+e36*e21*e05-e20*e05*e37+e20*e04*e38+e30*e04*e28-e20*e35*e07+e33*e22*e07+e30*e24*e08-e30*e25*e07-e23*e31*e08+e23*e32*e07+e00*e34*e28+e06*e21*e35+e06*e31*e25-e36*e02*e24+e26*e01*e35-e36*e22*e04+e26*e31*e05-e26*e02*e34+e20*e34*e08-e30*e05*e27;
      A[9 + 10*14]=e33*e22*e17+e33*e12*e27+e16*e21*e35-e16*e22*e34-e16*e32*e24+e23*e32*e17-e23*e11*e38-e23*e31*e18+e23*e12*e37-e13*e21*e38-e13*e31*e28+e13*e22*e37+e36*e21*e15-e36*e12*e24+e36*e11*e25-e26*e12*e34-e20*e35*e17+e20*e14*e38+e20*e34*e18+e30*e24*e18-e30*e15*e27-e30*e25*e17+e30*e14*e28-e33*e21*e18+e10*e34*e28+e10*e24*e38-e10*e35*e27-e10*e25*e37-e20*e15*e37-e26*e32*e14+e26*e11*e35+e26*e31*e15-e36*e22*e14+e13*e32*e27+e16*e31*e25-e33*e11*e28;
      A[9 + 10*15]=-e20*e35*e27-e20*e25*e37+e20*e34*e28+e20*e24*e38+e30*e24*e28-e30*e25*e27+e23*e32*e27+e23*e22*e37-e23*e31*e28-e23*e21*e38+e33*e22*e27-e26*e22*e34-e26*e32*e24+e26*e21*e35+e26*e31*e25-e36*e22*e24+e36*e21*e25-e33*e21*e28;
      A[9 + 10*16]=-e33*e01*e38-e03*e31*e38+e00*e34*e38+e33*e32*e07+e03*e32*e37+e06*e31*e35-e00*e35*e37-e36*e32*e04-e06*e32*e34-e36*e02*e34+e36*e01*e35+e36*e31*e05+e30*e04*e38+e30*e34*e08-e33*e31*e08+e33*e02*e37-e30*e05*e37-e30*e35*e07;
      A[9 + 10*17]=-e33*e31*e18-e33*e11*e38+e10*e34*e38+e30*e14*e38-e10*e35*e37-e30*e15*e37-e13*e31*e38+e13*e32*e37-e30*e35*e17+e33*e12*e37+e30*e34*e18+e33*e32*e17+e16*e31*e35-e16*e32*e34-e36*e12*e34-e36*e32*e14+e36*e11*e35+e36*e31*e15;
      A[9 + 10*18]=-e20*e35*e37+e20*e34*e38+e30*e24*e38-e30*e35*e27-e30*e25*e37+e30*e34*e28+e23*e32*e37-e23*e31*e38-e33*e21*e38-e33*e31*e28+e33*e22*e37+e33*e32*e27+e26*e31*e35-e26*e32*e34-e36*e22*e34-e36*e32*e24+e36*e21*e35+e36*e31*e25;
      A[9 + 10*19]=-e33*e31*e38-e30*e35*e37+e36*e31*e35+e33*e32*e37+e30*e34*e38-e36*e32*e34;
   } // end extractCubicCoefficients()


   inline void
   rearrangeMonomials(double * A) /* A should be 10*20 */
   {
      /* copy columns to a new A matrix as 
         P = [0 3 1 2 4 10 6 12 5 11 7 13 16 8 14 17 9 15 18 19];
      */

      double newA[20];
	
      for (int v = 0; v < 10; ++v)
      {
         newA[0] = A[v+10*0];
         newA[1] = A[v+10*3];
         newA[2] = A[v+10*1];
         newA[3] = A[v+10*2];
         newA[4] = A[v+10*4];
         newA[5] = A[v+10*10];
         newA[6] = A[v+10*6];
         newA[7] = A[v+10*12];
         newA[8] = A[v+10*5];
         newA[9] = A[v+10*11];
         newA[10] = A[v+10*7];
         newA[11] = A[v+10*13];
         newA[12] = A[v+10*16];
         newA[13] = A[v+10*8];
         newA[14] = A[v+10*14];
         newA[15] = A[v+10*17];
         newA[16] = A[v+10*9];
         newA[17] = A[v+10*15];
         newA[18] = A[v+10*18];
         newA[19] = A[v+10*19];

         A[v+10*0] = newA[0];
         A[v+10*1] = newA[1];
         A[v+10*2] = newA[2];
         A[v+10*3] = newA[3];
         A[v+10*4] = newA[4];
         A[v+10*5] = newA[5];
         A[v+10*6] = newA[6];
         A[v+10*7] = newA[7];
         A[v+10*8] = newA[8];
         A[v+10*9] = newA[9];
         A[v+10*10] = newA[10];
         A[v+10*11] = newA[11];
         A[v+10*12] = newA[12];
         A[v+10*13] = newA[13];
         A[v+10*14] = newA[14];
         A[v+10*15] = newA[15];
         A[v+10*16] = newA[16];
         A[v+10*17] = newA[17];
         A[v+10*18] = newA[18];
         A[v+10*19] = newA[19];
      } // end for (v)
   } // rearrangeMonomials()

// Access A in column major (!) mode
#define MAT_A(i, j) A[(i) + (j)*10]

   inline void
   gaussEliminationPass1(double * A)
   {
      int i, j, k;

      // Pass 1: Generate a upper right triangular matrix
      for (i = 0; i < 10; ++i)
      {
         int pivot_row = i;
         double pivot_elem = fabs(MAT_A(i, i));
         // Search for the largest pivot element in column i
         for (k = i; k < 10; ++k)
         {
            double a = fabs(MAT_A(k, i));
            if (a > pivot_elem)
            {
               pivot_elem = a;
               pivot_row  = k;
            }
         } // end for (k)

         if (i != pivot_row)
         {
            // Exchange row i and pivot_row
            for (j = 0; j < 20; ++j)
               swap(MAT_A(i, j), MAT_A(pivot_row, j));
         }

         double pivot = MAT_A(i, i);
         MAT_A(i, i) = 1.0;
         for (j = i+1; j < 20; ++j)
            MAT_A(i, j) /= pivot;

         for (k = i+1; k < 10; ++k)
         {
            double q = MAT_A(k, i);
            MAT_A(k, i) = 0.0;
            for (j = i+1; j < 20; ++j)
               MAT_A(k, j) -= q*MAT_A(i, j);
         }

      } // end for (i)
   } // end gaussEliminationPass1()

   void
   gaussEliminationPass2(double * A)
   {
      // Pass 2: Remove additional elements above the diagonal
      int const unhandledTopTows = 4;
      for (int i = 9; i > unhandledTopTows; --i)
      {
         for (int k = unhandledTopTows; k < i; ++k)
         {
            double q = MAT_A(k, i);
            for (int j = k; j < 20; ++j)
               MAT_A(k, j) -= q*MAT_A(i, j);
         }
      }
   } // end gaussEliminationPass2()

   void
   gaussEliminationOnA(double * A)
   {
      gaussEliminationPass1(A);
      gaussEliminationPass2(A);
   }

#undef MAT_A

   // Multiplication of 2 polynomials by convolution of their coefficients
   inline void
   conv(double const * v1, int m, double const * v2, int n, double * c, int sz3)
   {
      //: c should be in the size of (sz1+sz2-1);
      //: this constraint must be checked before call
      //: this function.

      assert(sz3 == m+n-1);

      int j_begin = 0;
      int j_end = 0; 

      for (int k = 0; k < sz3; ++k)
      {
         j_begin = std::max(0, k+1-n);
         j_end   = std::min(k+1, m);
         c[k]    = 0.0;

         for(int j = j_begin; j < j_end; ++j)
            c[k] += v1[j] * v2[k-j];
      }
   } // end conv()

   void displayVector(double const * v, int const sz)
   {
      cout << "[ ";
      for (int i = 0; i < sz; ++i)
         cout << v[i] << " ";
      cout << "]" << endl;
   }

   void
   solvePolynomial(double const * A, int& nSolutions, double * XX, double * YY, double * ZZ)
   {
      /* a. B must be in size of 3*13. 
         and makes it stored row by row.
         b. Poly must be of size 11;
      */
      //: no checking of the inputs right now, maybe later. 

      double B[3*13]; //: it's not the same B as in paper, it's mid-ware.
      double poly[11]; /* the 11 dim vector for the equation. */

      double b11[4], b12[4], b13[5];
      double b21[4], b22[4], b23[5];
      double b31[4], b32[4], b33[5];
	
      double con_11_22[7]; double con_11_22_33[11];
      double con_11_23[8]; double con_11_23_32[11];
      double con_12_23[8]; double con_12_23_31[11];
      double con_12_21[7]; double con_12_21_33[11];
      double con_13_21[8]; double con_13_21_32[11];
      double con_13_22[8]; double con_13_22_31[11];	

      /****************************************/
      /* make up the B matrix. */
      /* make sure A is stored column by column. */
      // 1. first row of B. 13 items.
      B[0*13+0] = -A[5+10*10];
      B[0*13+1] =  A[4+10*10]-A[5+10*11];
      B[0*13+2] =  A[4+10*11]-A[5+10*12];
      B[0*13+3] =  A[4+10*12];
      B[0*13+4] = -A[5+10*13];
      B[0*13+5] =  A[4+10*13]-A[5+10*14];
      B[0*13+6] =  A[4+10*14]-A[5+10*15];
      B[0*13+7] =  A[4+10*15];
      B[0*13+8] = -A[5+10*16];
      B[0*13+9] =  A[4+10*16]-A[5+10*17];
      B[0*13+10]=  A[4+10*17]-A[5+10*18];
      B[0*13+11]=  A[4+10*18]-A[5+10*19];
      B[0*13+12]=  A[4+10*19];

      //: 2nd row. 13 items.
      B[1*13+0] =-A[7+10*10];
      B[1*13+1] = A[6+10*10]-A[7+10*11];
      B[1*13+2] = A[6+10*11]-A[7+10*12];
      B[1*13+3] = A[6+10*12];
      B[1*13+4] =-A[7+10*13];
      B[1*13+5] = A[6+10*13]-A[7+10*14];
      B[1*13+6] = A[6+10*14]-A[7+10*15];
      B[1*13+7] = A[6+10*15];
      B[1*13+8] =-A[7+10*16];
      B[1*13+9] = A[6+10*16]-A[7+10*17];
      B[1*13+10]= A[6+10*17]-A[7+10*18];
      B[1*13+11]= A[6+10*18]-A[7+10*19];
      B[1*13+12]= A[6+10*19];
	
      //: 3rd row. 13 items. 
	
      B[2*13+0] =-A[9+10*10];
      B[2*13+1] = A[8+10*10]-A[9+10*11];
      B[2*13+2] = A[8+10*11]-A[9+10*12];
      B[2*13+3] = A[8+10*12];
      B[2*13+4] =-A[9+10*13];
      B[2*13+5] = A[8+10*13]-A[9+10*14];
      B[2*13+6] = A[8+10*14]-A[9+10*15]; 
      B[2*13+7] = A[8+10*15];
      B[2*13+8] =-A[9+10*16];
      B[2*13+9] = A[8+10*16]-A[9+10*17];
      B[2*13+10]= A[8+10*17]-A[9+10*18];
      B[2*13+11]= A[8+10*18]-A[9+10*19];
      B[2*13+12]= A[8+10*19];

      //: end of making B. 
      //: B will be returned.
      /****************************************/
      //: now making up polynomial vector.
      for(int i=0; i<4; i++)
         b11[i] = B[0*13+i];	
      for(int i=0; i<4; i++)
         b12[i] = B[0*13+4+i];
      for(int i=0; i<5; i++)
         b13[i] = B[0*13+8+i];
      //: b11 b13 b13 done. 

      for(int i=0; i<4; i++)
         b21[i] = B[1*13+i];
      for(int i=0; i<4; i++)
         b22[i] = B[1*13+4+i];
      for(int i=0; i<5; i++)
         b23[i] = B[ 1*13+8+i ];
      //: b21 b22 b23 done.

      for(int i=0; i<4; i++)
         b31[i] = B[2*13+i];
      for(int i=0; i<4; i++)
         b32[i] = B[2*13+4+i];		
      for(int i=0; i<5; i++)
         b33[i] = B[2*13+8+i];
      //: b31 b32 b33 done.

//       cout << "b11 = "; displayVector(b11, 4);
//       cout << "b12 = "; displayVector(b12, 4);
//       cout << "b13 = "; displayVector(b13, 5);
//       cout << "b21 = "; displayVector(b21, 4);
//       cout << "b22 = "; displayVector(b22, 4);
//       cout << "b23 = "; displayVector(b23, 5);
//       cout << "b31 = "; displayVector(b31, 4);
//       cout << "b32 = "; displayVector(b32, 4);
//       cout << "b33 = "; displayVector(b33, 5);


      /****************************************/
      //: now convolve for the coefficients.
      conv(b11, 4, b22, 4, con_11_22, 7);
      conv(b11, 4, b23, 5, con_11_23, 8);
      conv(b12, 4, b23, 5, con_12_23, 8);
      conv(b12, 4, b21, 4, con_12_21, 7);
      conv(b13, 5, b21, 4, con_13_21, 8);
      conv(b13, 5, b22, 4, con_13_22, 8);

//       cout << "con_11_22 = "; displayVector(con_11_22, 7);
//       cout << "con_11_23 = "; displayVector(con_11_23, 8);
//       cout << "con_12_23 = "; displayVector(con_12_23, 8);
//       cout << "con_12_21 = "; displayVector(con_12_21, 7);
//       cout << "con_13_21 = "; displayVector(con_13_21, 8);
//       cout << "con_13_22 = "; displayVector(con_13_22, 8);
	
      conv(con_11_22, 7, b33, 5, con_11_22_33, 11);
      conv(con_11_23, 8, b32, 4, con_11_23_32, 11);
      conv(con_12_23, 8, b31, 4, con_12_23_31, 11);
      conv(con_12_21, 7, b33, 5, con_12_21_33, 11);
      conv(con_13_21, 8, b32, 4, con_13_21_32, 11);
      conv(con_13_22, 8, b31, 4, con_13_22_31, 11);

      for (int i = 0; i < 11; ++i)
      {
         poly[i] = (con_11_22_33[i] - con_11_23_32[i] + con_12_23_31[i]
                    - con_12_21_33[i] + con_13_21_32[i] - con_13_22_31[i]);
      }	

//       cout << "con_11_22_33 = "; displayVector(con_11_22_33, 11);
//       cout << "con_11_23_32 = "; displayVector(con_11_23_32, 11);
//       cout << "con_12_23_31 = "; displayVector(con_12_23_31, 11);

      //cout.precision(15);
      //cout << "poly = "; displayVector(poly, 11);

      //: now the 10 degree polynomial has been obtained. solve it (using Sturm sequences).

      // We need to reverse the coefficients to comply with the root finder.
      double c[11];
      for(int i = 0; i < 11; ++i) c[i] = poly[10-i];
      //cout << "c = "; displayVector(c, 11);

      // Divide everything by the leading coefficient. In some cases (e.g. standard stereo setup)
      // the leading coefficient is extremely small and without normalization the root finding
      // procedure might reduce the degree of the polynomial in those cases.
      {
         int order = 10;
         while (fabs(c[order]) < 1e-12) --order;
         double const denom = c[order];
         for (int i = 0; i <= 10; ++i) c[i] /= denom;
      }
      vector<double> realRoots;
      V3D::RootFindingParameters<double> params;
      params.maxBisectionIterations = 40;
      try
      {
         V3D::computeRealRootsOfPolynomial(10, c, realRoots, params);
      }
      catch (...)
      {
         cerr << "5-point method: got exception from V3D::computeRealRootsOfPolynomial()." << endl;
         realRoots.clear();
      }

      nSolutions = realRoots.size();
//       cout << "nSolutions = " << nSolutions << endl;
//       displayVector(&realRoots[0], nSolutions);

      if (nSolutions == 0) return;

      for (int i = 0; i < nSolutions; ++i) ZZ[i] = realRoots[i];

      ////////////////////////////////////////////////////////
      //: with the up to ten real solutions, get their corresponding x and y. 
      //: again, SVD is used. 
      double  cz;
      Vector<double> curr(3);
      Matrix<double> BT(3, 3);

      for (int i = 0; i < nSolutions; ++i)
      {
         cz = ZZ[i];

         BT[0][0] = b11[0]*(cz*cz*cz) + b11[1]*(cz*cz) + b11[2]*cz + b11[3];
         BT[0][1] = b12[0]*(cz*cz*cz) + b12[1]*(cz*cz) + b12[2]*cz + b12[3];
         BT[0][2] = b13[0]*(cz*cz*cz*cz) + b13[1]*(cz*cz*cz) + b13[2]*(cz*cz) + b13[3]*cz + b13[4];

         BT[1][0] =  b21[0]*(cz*cz*cz) + b21[1]*(cz*cz) + b21[2]*cz + b21[3];
         BT[1][1] =  b22[0]*(cz*cz*cz) + b22[1]*(cz*cz) + b22[2]*cz + b22[3];
         BT[1][2] =  b23[0]*(cz*cz*cz*cz) + b23[1]*(cz*cz*cz) + b23[2]*(cz*cz) + b23[3]*cz + b23[4];

         BT[2][0] =  b31[0]*(cz*cz*cz) + b31[1]*(cz*cz) + b31[2]*cz + b31[3];
         BT[2][1] =  b32[0]*(cz*cz*cz) + b32[1]*(cz*cz) + b32[2]*cz + b32[3];
         BT[2][2] =  b33[0]*(cz*cz*cz*cz) + b33[1]*(cz*cz*cz) + b33[2]*(cz*cz) + b33[3]*cz + b33[4];

         SVD<double> svd(BT);

#if 0
         bool res = svd.GetNullvector(curr);
         if (!res) throw V3D_Exception("5-point error: unable to recover x and y from z.\n");
#else
         // Because the overall scale is not set, the smallest singular value might be still
         // significantlty larger than 0. Hence we always report the right singular vector for
         // the 3rd singular value.
         Matrix<double> const& V = svd.getV();
         curr[0] = V(1, 3);
         curr[1] = V(2, 3);
         curr[2] = V(3, 3);
#endif

         curr[0] /= curr[2]; // normalize it. 
         curr[1] /= curr[2];

         XX[i] = curr[0];
         YY[i] = curr[1];
      } // end for (i)
   } // end solvePolynomial()

//----------------------------------------------------------------------
// Relative pose nonlinear refinement
//----------------------------------------------------------------------

   using V3D::computeEssentialFromRelativePose;

   struct RelativePoseMinimizer : public V3D::SimpleLevenbergOptimizer
   {
         RelativePoseMinimizer(vector<Vector2d> const& left,
                               vector<Vector2d> const& right,
                               vector<Vector2d> const& leftUnnormalized,
                               vector<Vector2d> const& rightUnnormalized,
                               Matrix3x3d const& Kleft,
                               Matrix3x3d const& Kright,
                               double sampsonInlierThreshold)
            : V3D::SimpleLevenbergOptimizer(left.size(), 6), // R and t
              _left(left), _right(right),
              _leftUnnormalized(leftUnnormalized), _rightUnnormalized(rightUnnormalized),
              _Kleft(Kleft), _Kright(Kright),
              _invKleft(invertedMatrix(Kleft)), _invKright_t(invertedMatrix(Kright).transposed()),
              _sampsonInlierThreshold(sampsonInlierThreshold)
         {
            fillVector(0.0, observation);
         }

         virtual void evalFunction(Vector<double>& res)
         {
            Matrix3x3d const E = computeEssentialFromRelativePose(_currentR, _currentT);
            Matrix3x3d const Et = E.transposed();

            Vector3d Ep, Etq;

            for (size_t k = 0; k < res.size(); ++k)
            {
               Vector2d const& p = _left[k];
               Vector2d const& q = _right[k];

               multiply_A_v_affine(E, p, Ep);
               multiply_A_v_affine(Et, q, Etq);

               double const num   = q[0]*Ep[0] + q[1]*Ep[1] + Ep[2];
               double const denom = sqrt(Ep[0]*Ep[0] + Ep[1]*Ep[1] + Etq[0]*Etq[0] + Etq[1]*Etq[1]);

               res[k] = num/denom;
            } // end for (k)
         } // end evalFunction()

         virtual void fillWeights(Vector<double>& w)
         {
            Matrix3x3d const E = computeEssentialFromRelativePose(_currentR, _currentT);
            Matrix3x3d const F = _invKright_t * E * _invKleft;
            Matrix3x3d const Ft = F.transposed();

            Vector3d Fp, Ftq;

            for (unsigned int k = 0; k < w.size(); ++k)
            {
               Vector2d const& p = _leftUnnormalized[k];
               Vector2d const& q = _rightUnnormalized[k];

               multiply_A_v_affine(F, p, Fp);
               multiply_A_v_affine(Ft, q, Ftq);

               double const num   = q[0]*Fp[0] + q[1]*Fp[1] + Fp[2];
               double const denom = sqrt(Fp[0]*Fp[0] + Fp[1]*Fp[1] + Ftq[0]*Ftq[0] + Ftq[1]*Ftq[1]);

               double const e = num/denom;
               w[k] = (abs(e) < _sampsonInlierThreshold) ? 1.0 : sqrt(_sampsonInlierThreshold / abs(e));
            } // end for (k)
         }

         virtual void fillJacobian(Matrix<double>& J)
         {
            Matrix3x3d const& R = _currentR;
            Matrix3x3d const  E = computeEssentialFromRelativePose(_currentR, _currentT);
            Matrix3x3d const  Et = E.transposed();

            Matrix<double> innerDer(9, 6, 0.0); // dE/dOmega and dE/dT

            // dE/dOmega_x
            innerDer[0][0] = 0; innerDer[1][0] = E[0][2]; innerDer[2][0] = -E[0][1];
            innerDer[3][0] = 0; innerDer[4][0] = E[1][2]; innerDer[5][0] = -E[1][1];
            innerDer[6][0] = 0; innerDer[7][0] = E[2][2]; innerDer[8][0] = -E[2][1];

            // dE/dOmega_y
            innerDer[0][1] = -E[0][2]; innerDer[1][1] = 0; innerDer[2][1] = E[0][0];
            innerDer[3][1] = -E[1][2]; innerDer[4][1] = 0; innerDer[5][1] = E[1][0];
            innerDer[6][1] = -E[2][2]; innerDer[7][1] = 0; innerDer[8][1] = E[2][0];

            // dE/dOmega_z
            innerDer[0][2] = E[0][1]; innerDer[1][2] = -E[0][0]; innerDer[2][2] = 0;
            innerDer[3][2] = E[1][1]; innerDer[4][2] = -E[1][0]; innerDer[5][2] = 0;
            innerDer[6][2] = E[2][1]; innerDer[7][2] = -E[2][0]; innerDer[8][2] = 0;

            // dE/dT_x
            innerDer[0][3] = 0;        innerDer[1][3] = 0;        innerDer[2][3] = 0;
            innerDer[3][3] = -R[2][0]; innerDer[4][3] = -R[2][1]; innerDer[5][3] = -R[2][2];
            innerDer[6][3] = R[1][0];  innerDer[7][3] = R[1][1];  innerDer[8][3] = R[1][2];

            // dE/dT_y
            innerDer[0][4] = R[2][0];  innerDer[1][4] = R[2][1];  innerDer[2][4] = R[2][2];
            innerDer[3][4] = 0;        innerDer[4][4] = 0;        innerDer[5][4] = 0;
            innerDer[6][4] = -R[0][0]; innerDer[7][4] = -R[0][1]; innerDer[8][4] = -R[0][2];

            // dE/dT_z
            innerDer[0][5] = -R[1][0]; innerDer[1][5] = -R[1][1]; innerDer[2][5] = -R[1][2];
            innerDer[3][5] = R[0][0];  innerDer[4][5] = R[0][1];  innerDer[5][5] = R[0][2];
            innerDer[6][5] = 0;        innerDer[7][5] = 0;        innerDer[8][5] = 0;

            Vector3d Ep, Etq;
            Matrix<double> outerDer(1, 9); // dSampson/dE

            Matrix<double> numDer(1, 9); // dNum/dE = d(q^t*E*p)/dE
            Matrix<double> sqrDenomDer(1, 9);
            Matrix<double> derivative(1, 6);

            for (size_t k = 0; k < J.num_rows(); ++k)
            {
               Vector2d const& p = _left[k];
               Vector2d const& q = _right[k];

               multiply_A_v_affine(E, p, Ep);
               multiply_A_v_affine(Et, q, Etq);

               double const num = q[0]*Ep[0] + q[1]*Ep[1] + Ep[2];

               numDer[0][0] = q[0]*p[0]; numDer[0][1] = q[0]*p[1]; numDer[0][2] = q[0];
               numDer[0][3] = q[1]*p[0]; numDer[0][4] = q[1]*p[1]; numDer[0][5] = q[1];
               numDer[0][6] =      p[0]; numDer[0][7] =      p[1]; numDer[0][8] = 1;

               sqrDenomDer[0][0] = 2*Ep[0]*p[0] + 2*Etq[0]*q[0];
               sqrDenomDer[0][1] = 2*Ep[0]*p[1] + 2*Etq[1]*q[0];
               sqrDenomDer[0][2] = 2*Ep[0];
               sqrDenomDer[0][3] = 2*Ep[1]*p[0] + 2*Etq[0]*q[1];
               sqrDenomDer[0][4] = 2*Ep[1]*p[1] + 2*Etq[1]*q[1];
               sqrDenomDer[0][5] = 2*Ep[1];
               sqrDenomDer[0][6] = 2*Etq[0];
               sqrDenomDer[0][7] = 2*Etq[1];
               sqrDenomDer[0][8] = 0.0;

               double const sqrDenom = Ep[0]*Ep[0] + Ep[1]*Ep[1] + Etq[0]*Etq[0] + Etq[1]*Etq[1];
               double const denom = sqrt(sqrDenom);
               double const invDenom = 1.0 / denom;
               double const invSqrDenom = 1.0 / sqrDenom;

               for (int j = 0; j < 9; ++j)
                  outerDer[0][j] = (numDer[0][j]*denom - num*0.5*invDenom*sqrDenomDer[0][j]) * invSqrDenom;

               multiply_A_B(outerDer, innerDer, derivative);

               for (int c = 0; c < 6; ++c) J[k][c] = derivative[0][c];
            } // end for (k)
         } // end fillJacobian()

         virtual double getParameterLength() const
         {
            // T is assumed to be normalized to 1, and R is a rotation matrix, i.e. with Frobenious norm 3.
            return 4.0;
         }

         virtual void updateCurrentParameters(Vector<double> const& delta)
         {
            Vector3d omega(delta[0], delta[1], delta[2]);

            Matrix3x3d const oldR(_currentR);

            Matrix3x3d dR;
            createRotationMatrixRodrigues(omega, dR);

            _currentR = oldR * dR;

            _currentT[0] += delta[3];
            _currentT[1] += delta[4];
            _currentT[2] += delta[5];

            normalizeVector(_currentT);
         }

         virtual void saveCurrentParameters()
         {
            _savedR = _currentR;
            _savedT = _currentT;
         }

         virtual void restoreCurrentParameters()
         {
            _currentR = _savedR;
            _currentT = _savedT;
         }

         vector<Vector2d> _left, _right;
         vector<Vector2d> _leftUnnormalized, _rightUnnormalized;

         Matrix3x3d const& _Kleft, _Kright;
         Matrix3x3d        _invKleft, _invKright_t;

         Matrix3x3d _currentR, _savedR;
         Vector3d   _currentT, _savedT;

         double _sampsonInlierThreshold;
   }; // end struct RelativePoseMinimizer

} // end namespace <>

//----------------------------------------------------------------------

namespace V3D
{

   bool
   computeEssentialsFromFiveCorrs(double const x1[5], double const y1[5],
                                  double const x2[5], double const y2[5],
                                  vector<Matrix3x3d>& Es)
   {
      double EE[4*9];
      double A[10*20];

      double x[10];
      double y[10];
      double z[10];

      Es.clear();

      int nSolutions = 0;

      getNullSpace(x1, y1, x2, y2, EE);
      extractCubicCoefficients(EE, A);

      rearrangeMonomials(A);
      gaussEliminationOnA(A);
//          cout << "A = ";
//          for (int i = 0; i < 10; ++i)
//          {
//             for (int j = 0; j < 20; ++j)
//                cout << A[i+10*j] << " ";
//             cout << endl;
//          }

      solvePolynomial(A, nSolutions, x, y, z);

      Matrix3x3d E;

      for (int i = 0; i < nSolutions; ++i)
      {
         //: make up an E by [x, y, z, 1].
         for (int r = 0; r < 3; ++r)
            for (int c = 0; c < 3; ++c)
            {
               int const j = 3*r + c;
               E(r+1, c+1) = x[i]*EE[0*9+j] + y[i]*EE[1*9+j] + z[i]*EE[2*9+j] + EE[3*9+j];
            }
         Es.push_back(E);	
      }
      return true;
   } // end computeEssentialsFromFiveCorrs()


   bool
   refineRelativePose(std::vector<Vector2d> const& left,
                      std::vector<Vector2d> const& right,
                      Matrix3x3d const& Kleft,
                      Matrix3x3d const& Kright,
                      Matrix3x3d& R,
                      Vector3d& T,
                      double sampsonInlierThreshold)
   {
      Matrix3x3d invKleft  = invertedMatrix(Kleft);
      Matrix3x3d invKright = invertedMatrix(Kright);

      size_t const size = left.size();

      std::vector<Vector2d> normLeft(left.size());
      std::vector<Vector2d> normRight(right.size());

      for (size_t i = 0; i < size; ++i)
      {
         multiply_A_v_projective(invKleft, left[i], normLeft[i]);
         multiply_A_v_projective(invKright, right[i], normRight[i]);
      }

      RelativePoseMinimizer opt(normLeft, normRight, left, right, 
                                Kleft, Kright, sampsonInlierThreshold);
      opt._currentR = R;
      opt._currentT = T;

      //optimizerVerbosenessLevel = 1;
      opt.minimize();
      //optimizerVerbosenessLevel = 0;

      R = opt._currentR;
      T = opt._currentT;

      return true;
   } // end refineRelativePose()

} // end namespace V3D

//----------------------------------------------------------------------

namespace
{

   inline void
   triangulatePointExact(Matrix3x3d const& E, Matrix3x4d const& P,
                         Vector3d const& p, Vector3d const& q,
                         Vector4d& Q)
   {
      Matrix3x3d E1;
      // E1 = diag(1, 1, 0)*E
      E1[0][0] = E[0][0]; E1[0][1] = E[0][1]; E1[0][2] = E[0][2];
      E1[1][0] = E[1][0]; E1[1][1] = E[1][1]; E1[1][2] = E[1][2];
      E1[2][0] = 0;       E1[2][1] = 0;       E1[2][2] = 0;

      Vector3d p1 = E1 * p;
      Vector3d c;
      makeCrossProductVector(q, p1, c);

      Vector4d C = P.transposed() * c;

      Q[0] = p[0]*C[3];
      Q[1] = p[1]*C[3];
      Q[2] = p[2]*C[3];
      Q[3] = -(p[0]*C[0] + p[1]*C[1] + p[2]*C[2]);
   } // end triangulatePointExact()

} // end namespace <>

namespace V3D
{

   void
   computeEssentialSVD(Matrix3x3d const& E, Matrix3x3d& U, Matrix3x3d& V)
   {
      Vector3d ea, eb, ec;

      ea = E.row(0);
      eb = E.row(1);
      ec = E.row(2);

      Vector3d eaxeb, eaxec, ebxec;
      makeCrossProductVector(ea, eb, eaxeb);
      makeCrossProductVector(ea, ec, eaxec);
      makeCrossProductVector(eb, ec, ebxec);

      Vector3d * x = &eaxeb;
      Vector3d * y = &ea;
      double maxLength = norm_L2(eaxeb);

      double len = norm_L2(eaxec);
      if (len > maxLength) { maxLength = len; x = &eaxec; y = &ea; }
      len = norm_L2(ebxec);
      if (len > maxLength) { maxLength = len; x = &ebxec; y = &eb; }

      Vector3d va, vb, vc;

      vc = (1.0 / maxLength) * (*x);
      va = *y;
      normalizeVector(va);
      makeCrossProductVector(vc, va, vb);

      Vector3d ua = E * va;
      Vector3d ub = E * vb;

      normalizeVector(ua);
      normalizeVector(ub);

      Vector3d uc;
      makeCrossProductVector(ua, ub, uc);

      V.setColumnSlice(0, 3, 0, va);
      V.setColumnSlice(0, 3, 1, vb);
      V.setColumnSlice(0, 3, 2, vc);
      U.setColumnSlice(0, 3, 0, ua);
      U.setColumnSlice(0, 3, 1, ub);
      U.setColumnSlice(0, 3, 2, uc);
   } // end computeEssentialSVD()

   Matrix3x3d makeD_Matrix()
   {
      Matrix3x3d D;
      makeZeroMatrix(D);
      D[0][1] = 1;
      D[1][0] = -1;
      D[2][2] = 1;
      return D;
   }

   int
   getExactConfiguration(Matrix3x3d const& E, Matrix3x3d const& U, Matrix3x3d const& V,
                         double x1, double y1, double x2, double y2)
   {
      Vector3d p, q, t1;

      p[0] = x1; p[1] = y1; p[2] = 1.0;
      q[0] = x2; q[1] = y2; q[2] = 1.0;

      static Matrix3x3d const D(makeD_Matrix());

      // R1 = U D V'
      Matrix3x3d R1 = U * D * V.transposed();
      t1 = U.col(2);

      Matrix3x4d Pa;
      Pa(1, 1) = R1(1, 1); Pa(1, 2) = R1(1, 2); Pa(1, 3) = R1(1, 3); Pa(1, 4) = t1[0];
      Pa(2, 1) = R1(2, 1); Pa(2, 2) = R1(2, 2); Pa(2, 3) = R1(2, 3); Pa(2, 4) = t1[1];
      Pa(3, 1) = R1(3, 1); Pa(3, 2) = R1(3, 2); Pa(3, 3) = R1(3, 3); Pa(3, 4) = t1[2];

      Vector4d Q;
      triangulatePointExact(E, Pa, p, q, Q);
      Q[0] /= Q[3]; Q[1] /= Q[3]; Q[2] /= Q[3]; Q[3] = 1.0;

      double c1 = Q[2]*Q[3];
      double c = Pa(3, 1)*Q[0] + Pa(3, 2)*Q[1] + Pa(3, 3)*Q[2] + Pa(3, 4)*Q[3];
      double c2 = c * Q[3];
      if (c1 >= 0 && c2 >= 0) return 0; // P = (R1, t)
      if (c1 < 0 && c2 < 0) return 1;   // P = (R1, -t)
      c = -(2*V(1, 3)*Q[0] + 2*V(2, 3)*Q[1] + 2*V(3, 3)*Q[2] + Q[3]);
      if (Q[2]*c >= 0) return 2; // P = (R2, t)
      return 3; // P = (R2, -t)
   } // end getExactConfiguration()

   void
   relativePoseFromEssential(Matrix3x3d const& U, Matrix3x3d const& V,
                             int configuration,
                             Matrix3x3d& R, Vector3d& T)
   {
      static Matrix3x3d const D(makeD_Matrix());
      static Matrix3x3d const Dt(D.transposed());

      switch (configuration)
      {
         case 0:
         case 1:
            // R1 = U D V'
            R = U * D * V.transposed();
            break;
         case 2:
         case 3:
            // R2 = U D' V'
            R = U * Dt * V.transposed();
            break;
      }

      switch (configuration)
      {
         case 0:
         case 2:
            T = U.col(2);
            break;
         case 1:
         case 3:
            T = (-1.0) * U.col(2);
            break;
      }
      normalizeVector(T);
   } // end relativePoseFromEssential()

   bool
   relativePoseFromEssential(Matrix3x3d const& E, int nCorrs,
                             double const * x1, double const * y1,
                             double const * x2, double const * y2,
                             Matrix3x3d& R, Vector3d& T)
   {
      assert(nCorrs >= 1);

      Matrix3x3d U, V;

      computeEssentialSVD(E, U, V);

      int const conf0 = getExactConfiguration(E, U, V, x1[0], y1[0], x2[0], y2[0]);

      for (int i = 1; i < nCorrs; ++i)
      {
         int const conf = getExactConfiguration(E, U, V, x1[i], y1[i], x2[i], y2[i]);
         if (conf != conf0)
         {
            makeZeroMatrix(R);
            makeZeroVector(T);
            return false;
         }
      } // end for (i)

      relativePoseFromEssential(U, V, conf0, R, T);

      return true;
   } // end relativePoseFromEssential()

} // end namespace V3D


//**********************************************************************
// Fundamental matrix
//**********************************************************************

namespace V3D
{

   void
   computeFundamentalsFrom7Corrs(double const x1[7], double const y1[7], double const x2[7], double const y2[7],
                                 std::vector<Matrix3x3d>& Fs)
   {
      typedef InlineMatrix<double, 7, 9> Matrix7x9d;

      Fs.clear();

      Matrix7x9d U7;

      for (int i = 0; i < 7; ++i)
      {
         U7[i][0] = x1[i]*x2[i];
         U7[i][1] = y1[i]*x2[i];
         U7[i][2] = x2[i];
         U7[i][3] = x1[i]*y2[i];
         U7[i][4] = y1[i]*y2[i];
         U7[i][5] = y2[i];
         U7[i][6] = x1[i];
         U7[i][7] = y1[i];
         U7[i][8] = 1;
      }

      // NOTE: TNT's SVD requires #rows >= #columns, so create a square equation matrix by filling in zeros.
      Matrix<double> U9(9, 9, 0.0);
      copyMatrixSlice(U7, 0, 0, 7, 9, U9, 0, 0);

      SVD<double> svd(U9);

      Vector<double> S;
      svd.getSingularValues(S);
      if (S[2] < 1e-6)
      {
         cerr << "computeFundamentals(): degenerate configuration." << endl;
         return;
      }

      Matrix<double> const& V = svd.getV();

      Matrix3x3d F1, F2;
      for (int i = 0; i < 3; ++i)
         for (int j = 0; j < 3; ++j)
         {
            F1[i][j] = V[i*3+j][7];
            F2[i][j] = V[i*3+j][8];
         }

      Matrix3x3d D;
      subtractMatrices(F1, F2, D);

      // a0*a^3 + a1*a^2 + a2*a + a3
      double a0 = (D[0][0]*D[1][1]*D[2][2]-D[1][0]*D[0][1]*D[2][2]-D[0][0]*D[2][1]*D[1][2]
                   +D[2][0]*D[0][1]*D[1][2]+D[1][0]*D[2][1]*D[0][2]
                   -D[2][0]*D[1][1]*D[0][2]);
      double a1 = (D[0][0]*D[1][1]*F2[2][2]-D[1][0]*D[0][1]*F2[2][2]
                   +D[0][0]*F2[1][1]*D[2][2]
                   +F2[0][0]*D[1][1]*D[2][2]
                   -D[1][0]*F2[0][1]*D[2][2]
                   -F2[1][0]*D[0][1]*D[2][2]
                   -D[0][0]*D[2][1]*F2[1][2]
                   +D[2][0]*D[0][1]*F2[1][2]
                   -D[0][0]*F2[2][1]*D[1][2]
                   -F2[0][0]*D[2][1]*D[1][2]
                   +D[2][0]*F2[0][1]*D[1][2]
                   +F2[2][0]*D[0][1]*D[1][2]
                   +D[1][0]*D[2][1]*F2[0][2]
                   -D[2][0]*D[1][1]*F2[0][2]
                   +D[1][0]*F2[2][1]*D[0][2]
                   +F2[1][0]*D[2][1]*D[0][2]
                   -D[2][0]*F2[1][1]*D[0][2]
                   -F2[2][0]*D[1][1]*D[0][2]);
      double a2 = (D[0][0]*F2[1][1]*F2[2][2]+F2[0][0]*D[1][1]*F2[2][2]
                   -D[1][0]*F2[0][1]*F2[2][2]
                   -F2[1][0]*D[0][1]*F2[2][2]
                   +F2[0][0]*F2[1][1]*D[2][2]
                   -F2[1][0]*F2[0][1]*D[2][2]
                   -D[0][0]*F2[2][1]*F2[1][2]
                   -F2[0][0]*D[2][1]*F2[1][2]
                   +D[2][0]*F2[0][1]*F2[1][2]
                   +F2[2][0]*D[0][1]*F2[1][2]
                   -F2[0][0]*F2[2][1]*D[1][2]
                   +F2[2][0]*F2[0][1]*D[1][2]
                   +D[1][0]*F2[2][1]*F2[0][2]
                   +F2[1][0]*D[2][1]*F2[0][2]
                   -D[2][0]*F2[1][1]*F2[0][2]
                   -F2[2][0]*D[1][1]*F2[0][2]
                   +F2[1][0]*F2[2][1]*D[0][2]
                   -F2[2][0]*F2[1][1]*D[0][2]);
      double a3 = (F2[0][0]*F2[1][1]*F2[2][2]-F2[1][0]*F2[0][1]*F2[2][2]
                   -F2[0][0]*F2[2][1]*F2[1][2]
                   +F2[2][0]*F2[0][1]*F2[1][2]
                   +F2[1][0]*F2[2][1]*F2[0][2]
                   -F2[2][0]*F2[1][1]*F2[0][2]);

      double roots[3];
      int const nRoots = getRealRootsOfCubicPolynomial(a0, a1, a2, a3, roots);

      if (nRoots == 0)
      {
         cerr << "computeFundamentals(): No roots found!" << endl;
      }

      for (unsigned i = 0; i < nRoots; ++i)
         Fs.push_back(roots[i]*F1 + (1.0-roots[i])*F2);

//       for (int i = 0; i < Fs.size(); ++i)
//       {
//          Matrix3x3d const& F = Fs[i];
//          for (int k = 0; k < 7; ++k)
//          {
//             Vector3d p(x1[k], y1[k], 1.0);
//             Vector3d q(x2[k], y2[k], 1.0);
//             Vector3d Fp = F*p;
//             double qFp = innerProduct(q, Fp);
//             cerr << qFp << " ";
//          }
//          cerr << endl;
//       }
   } // end computeFundamentalsFrom7Corrs()

} // end namespace V3D

//**********************************************************************
// Absolute pose (P3P)
//**********************************************************************

namespace
{

   inline double sqr(double x) { return x*x; }

   inline double pow3(double x) { return x*x*x; }

   inline double pow4(double x) { return sqr(x*x); }

   inline void
   fillAbsPosePolynomial(double d12, double d13, double d23,
                         double c12, double c13, double c23,
                         double a[5])
   {
      double const d1 = d12*d12;
      double const d2 = d13*d13;
      double const d3 = d23*d23;

      double const c1 = 2*c12;
      double const c2 = 2*c13;
      double const c3 = 2*c23;

      // These expressions were derived using maxima using the following instructions:
      // f1:x1^2+x2^2-c1*x1*x2-d1;
      // f2:x1^2+x3^2-c2*x1*x3-d2;
      // f3:x2^2+x3^2-c2*x2*x3-d3;
      // h:resultant(f2, f3, x3);
      // g:resultant(f1, h, x2);
      // Then, a[i] = factor(coeff(g, x1, 2*i)), since g is a polynomial in x1^2.

      a[4] = sqr(c3*c3-c1*c2*c3+c2*c2+c1*c1-4);

      a[3] = (sqr(c3)-c1*c2*c3+sqr(c2)+sqr(c1)-4)*(c1*c2*c3*d3-sqr(c1)*sqr(c2)*d3+2*sqr(c2)*d3
                                                   +2*sqr(c1)*d3-8*d3-2*sqr(c3)*d2
                                                   +c1*c2*c3*d2-2*sqr(c1)*d2+8*d2
                                                   -2*sqr(c3)*d1+c1*c2*c3*d1
                                                   -2*sqr(c2)*d1+8*d1);

      a[2] = sqr(c2)*sqr(c3)*sqr(d3)+sqr(c1)*sqr(c3)*sqr(d3)-2*sqr(c3)*sqr(d3)-c1*pow3(c2)*c3*sqr(d3)
         -pow3(c1)*c2*c3*sqr(d3)+2*c1*c2*c3*sqr(d3)+pow4(c2)*sqr(d3)
         +3*sqr(c1)*sqr(c2)*sqr(d3)-10*sqr(c2)*sqr(d3)+pow4(c1)*sqr(d3)-10*sqr(c1)*sqr(d3)
         +24*sqr(d3)-c1*c2*pow3(c3)*d2*d3+sqr(c1)*sqr(c2)*sqr(c3)*d2*d3
         -4*sqr(c1)*sqr(c3)*d2*d3+12*sqr(c3)*d2*d3-c1*pow3(c2)*c3*d2*d3
         +2*pow3(c1)*c2*c3*d2*d3-4*c1*c2*c3*d2*d3-4*sqr(c1)*sqr(c2)*d2*d3
         +12*sqr(c2)*d2*d3-2*pow4(c1)*d2*d3+20*sqr(c1)*d2*d3-48*d2*d3
         -c1*c2*pow3(c3)*d1*d3+sqr(c1)*sqr(c2)*sqr(c3)*d1*d3-4*sqr(c2)*sqr(c3)*d1*d3
         +12*sqr(c3)*d1*d3+2*c1*pow3(c2)*c3*d1*d3-pow3(c1)*c2*c3*d1*d3
         -4*c1*c2*c3*d1*d3-2*pow4(c2)*d1*d3-4*sqr(c1)*sqr(c2)*d1*d3
         +20*sqr(c2)*d1*d3+12*sqr(c1)*d1*d3-48*d1*d3+pow4(c3)*sqr(d2)
         -c1*c2*pow3(c3)*sqr(d2)+sqr(c2)*sqr(c3)*sqr(d2)+3*sqr(c1)*sqr(c3)*sqr(d2)
         -10*sqr(c3)*sqr(d2)-pow3(c1)*c2*c3*sqr(d2)+2*c1*c2*c3*sqr(d2)
         +sqr(c1)*sqr(c2)*sqr(d2)-2*sqr(c2)*sqr(d2)+pow4(c1)*sqr(d2)-10*sqr(c1)*sqr(d2)
         +24*sqr(d2)+4*pow4(c3)*d1*d2-4*c1*c2*pow3(c3)*d1*d2
         +sqr(c1)*sqr(c2)*sqr(c3)*d1*d2+2*sqr(c2)*sqr(c3)*d1*d2+2*sqr(c1)*sqr(c3)*d1*d2
         -28*sqr(c3)*d1*d2-c1*pow3(c2)*c3*d1*d2-pow3(c1)*c2*c3*d1*d2
         +20*c1*c2*c3*d1*d2-12*sqr(c2)*d1*d2-12*sqr(c1)*d1*d2+48*d1*d2
         +pow4(c3)*sqr(d1)-c1*c2*pow3(c3)*sqr(d1)+3*sqr(c2)*sqr(c3)*sqr(d1)
         +sqr(c1)*sqr(c3)*sqr(d1)-10*sqr(c3)*sqr(d1)-c1*pow3(c2)*c3*sqr(d1)
         +2*c1*c2*c3*sqr(d1)+pow4(c2)*sqr(d1)+sqr(c1)*sqr(c2)*sqr(d1)-10*sqr(c2)*sqr(d1)
         -2*sqr(c1)*sqr(d1)+24*sqr(d1);

      a[1] = c1*c2*c3*pow3(d3)-2*sqr(c2)*pow3(d3)-2*sqr(c1)*pow3(d3)+8*pow3(d3)-sqr(c1)*sqr(c3)*d2*sqr(d3)
         +2*sqr(c3)*d2*sqr(d3)-c1*c2*c3*d2*sqr(d3)+4*sqr(c2)*d2*sqr(d3)
         +6*sqr(c1)*d2*sqr(d3)-24*d2*sqr(d3)-sqr(c2)*sqr(c3)*d1*sqr(d3)
         +2*sqr(c3)*d1*sqr(d3)-c1*c2*c3*d1*sqr(d3)+6*sqr(c2)*d1*sqr(d3)
         +4*sqr(c1)*d1*sqr(d3)-24*d1*sqr(d3)+2*sqr(c1)*sqr(c3)*sqr(d2)*d3
         -4*sqr(c3)*sqr(d2)*d3-c1*c2*c3*sqr(d2)*d3-2*sqr(c2)*sqr(d2)*d3
         -6*sqr(c1)*sqr(d2)*d3+24*sqr(d2)*d3+c1*c2*pow3(c3)*d1*d2*d3
         -16*sqr(c3)*d1*d2*d3+6*c1*c2*c3*d1*d2*d3-8*sqr(c2)*d1*d2*d3
         -8*sqr(c1)*d1*d2*d3+48*d1*d2*d3+2*sqr(c2)*sqr(c3)*sqr(d1)*d3
         -4*sqr(c3)*sqr(d1)*d3-c1*c2*c3*sqr(d1)*d3-6*sqr(c2)*sqr(d1)*d3
         -2*sqr(c1)*sqr(d1)*d3+24*sqr(d1)*d3-sqr(c1)*sqr(c3)*pow3(d2)+2*sqr(c3)*pow3(d2)
         +c1*c2*c3*pow3(d2)+2*sqr(c1)*pow3(d2)-8*pow3(d2)-2*pow4(c3)*d1*sqr(d2)
         +c1*c2*pow3(c3)*d1*sqr(d2)-sqr(c2)*sqr(c3)*d1*sqr(d2)+14*sqr(c3)*d1*sqr(d2)
         -5*c1*c2*c3*d1*sqr(d2)+2*sqr(c2)*d1*sqr(d2)+4*sqr(c1)*d1*sqr(d2)
         -24*d1*sqr(d2)-2*pow4(c3)*sqr(d1)*d2+c1*c2*pow3(c3)*sqr(d1)*d2
         -sqr(c1)*sqr(c3)*sqr(d1)*d2+14*sqr(c3)*sqr(d1)*d2-5*c1*c2*c3*sqr(d1)*d2
         +4*sqr(c2)*sqr(d1)*d2+2*sqr(c1)*sqr(d1)*d2-24*sqr(d1)*d2-sqr(c2)*sqr(c3)*pow3(d1)
         +2*sqr(c3)*pow3(d1)+c1*c2*c3*pow3(d1)+2*sqr(c2)*pow3(d1)-8*pow3(d1);

      a[0] = sqr(sqr(d3)-2*d2*d3-2*d1*d3+sqr(d2)-sqr(c3)*d1*d2+2*d1*d2+sqr(d1));
   } // end fillAbsPosePolynomial()



   inline Matrix2x3d
   commonDerivativeMatrix(Vector3d const& XX)
   {
      Matrix2x3d A;
      double c = 1.0 / (XX[2] * XX[2]);
      A[0][0] = c * XX[2]; A[0][1] = 0;         A[0][2] = c * -XX[0];
      A[1][0] = 0;         A[1][1] = c * XX[2]; A[1][2] = -c * XX[1];
      return A;
   }

   typedef InlineMatrix<double, 2, 6> Matrix2x6d;
   typedef InlineMatrix<double, 3, 6> Matrix3x6d;

   struct AbsolutePoseMinimizer : public V3D::SimpleLevenbergOptimizer
   {
         AbsolutePoseMinimizer(vector<Vector2f> const& points2d,
                               vector<Vector3d> const& points3d,
                               double inlierThreshold)
            : V3D::SimpleLevenbergOptimizer(2*points3d.size(), 6), // R and t
              _points3d(points3d), _inlierThreshold(inlierThreshold)
         {
            for (size_t k = 0; k < _points3d.size(); ++k)
            {
               observation[2*k+0] = points2d[k][0];
               observation[2*k+1] = points2d[k][1];
            }
         }

         virtual void evalFunction(Vector<double>& res)
         {
            for (size_t k = 0; k < _points3d.size(); ++k)
            {
               Vector3d const& X = _points3d[k];
               Vector3d const  XX = _currentR * X + _currentT;
               res[2*k+0] = XX[0] / XX[2];
               res[2*k+1] = XX[1] / XX[2];
            } // end for (k)
         } // end evalFunction()

         virtual void fillWeights(Vector<double>& w)
         {
            Vector2d Q;

            for (unsigned int k = 0; k < _points3d.size(); ++k)
            {
               Vector3d const& X = _points3d[k];
               Vector3d const  XX = _currentR * X + _currentT;
               Q[0] = XX[0] / XX[2];
               Q[1] = XX[1] / XX[2];

               Vector2d const P(observation[2*k+0], observation[2*k+1]);
               double const e = distance_L2(P, Q);

               w[2*k+0] = w[2*k+1] = (e < _inlierThreshold) ? 1.0 : sqrt(_inlierThreshold / e);
            } // end for (k)
         }

         virtual void fillJacobian(Matrix<double>& Jac)
         {
            // Jac is a (2*nCorrs) x 6 matrix

            Matrix3x3d J;
            Matrix2x6d F; // Holds the derivatives of the objective function wrt. the camera params
            Matrix3x6d T;
            Matrix2x3d A;

            for (size_t k = 0; k < _points3d.size(); ++k)
            {
               Vector3d const& X = _points3d[k];
               Vector3d const  RX = _currentR * X;
               Vector3d const  XX = RX + _currentT;

               // RX is transformed point without translation, since
               // d(dR * Rbase * X + t)/d angles = -J(Rbase * X) = -J(RX)
               makeCrossProductMatrix(RX, J);
               scaleMatrixIP(-1, J);
               // Now the transformation from world coords into camera space is x' = Rx + T
               // (instead of R(x-T)). Hence the derivative of x wrt. T is just the identity matrix
               // (not -R).
               makeIdentityMatrix(T);
               copyMatrixSlice(J, 0, 0, 3, 3, T, 0, 3);

               A = commonDerivativeMatrix(XX);
               multiply_A_B(A, T, F);

               copyMatrixSlice(F, 0, 0, 2, 6, Jac, 2*k, 0);
            } // end for (k)
         } // end fillJacobian()

         virtual double getParameterLength() const
         {
            // R is a rotation matrix, i.e. with Frobenious norm 3.
            return sqrt(3.0 + sqrNorm_L2(_currentT));
         }

         virtual void updateCurrentParameters(Vector<double> const& delta)
         {
            _currentT[0] += delta[0]; _currentT[1] += delta[1]; _currentT[2] += delta[2];

            Vector3d omega;
            omega[0] = delta[3]; omega[1] = delta[4]; omega[2] = delta[5];

            Matrix3x3d dR;
            createRotationMatrixRodrigues(omega, dR);
            _currentR = _currentR * dR;
         }

         virtual void saveCurrentParameters()
         {
            _savedR = _currentR;
            _savedT = _currentT;
         }

         virtual void restoreCurrentParameters()
         {
            _currentR = _savedR;
            _currentT = _savedT;
         }

         vector<Vector3d> const& _points3d;

         Matrix3x3d _currentR, _savedR;
         Vector3d   _currentT, _savedT;
         double const _inlierThreshold;
   }; // end struct AbsolutePoseMinimizer

} // end namespace <>

namespace V3D
{

   void
   computeAbsolutePose3Point(Vector2f const& p1, Vector2f const& p2, Vector2f const& p3, // Normalized image points
                             Vector3d const& X1, Vector3d const& X2, Vector3d const& X3, // 3D points
                             vector<Matrix3x4d>& RTs)
   {
       RTs.resize(8);
       int numRTs;
       computeAbsolutePose3Point(p1,p2,p3,X1,X2,X3,&RTs[0],RTs.size(),numRTs);
       RTs.resize(numRTs);
   }

   void
   computeAbsolutePose3Point(Vector2f const& p1, Vector2f const& p2, Vector2f const& p3, // Normalized image points
                             Vector3d const& X1, Vector3d const& X2, Vector3d const& X3, // 3D points
                             Matrix3x4d *RTs, int maxRTs, int &numRTs )
   {
      // Point distances
      double const d12 = distance_L2(X1, X2);
      double const d13 = distance_L2(X1, X3);
      double const d23 = distance_L2(X2, X3);

      Vector3d u1(p1[0], p1[1], 1.0);
      Vector3d u2(p2[0], p2[1], 1.0);
      Vector3d u3(p3[0], p3[1], 1.0);
      normalizeVector(u1);
      normalizeVector(u2);
      normalizeVector(u3);

      // Cosines of the angle between rays
      double const c12 = innerProduct(u1, u2);
      double const c13 = innerProduct(u1, u3);
      double const c23 = innerProduct(u2, u3);

      double coeffs[5];
      fillAbsPosePolynomial(d12, d13, d23, c12, c13, c23, coeffs);

      double roots[4];
      int nRootsX1 = getRealRootsOfQuarticPolynomial(coeffs[4], coeffs[3], coeffs[2], coeffs[1],
                                                     coeffs[0], roots);

      numRTs = 0;
      for (int i = 0; i < nRootsX1; ++i)
      {
         double const x = roots[i];
         if (x < 0) continue; // Should not happen, actually.
         double const x1 = sqrt(x);
         double rootsX2[2], rootsX3[2];
         int nRootsX2 = getRealRootsOfQuadraticPolynomial(1, -2*x1*c12, x1*x1-d12*d12, rootsX2);
         int nRootsX3 = getRealRootsOfQuadraticPolynomial(1, -2*x1*c13, x1*x1-d13*d13, rootsX3);

         if (nRootsX2 == 0 || nRootsX3 == 0) continue; // Should not happen, either

         double bestExcess = 1e30;
         double bestX2 = 0, bestX3 = 0;

         for (int i2 = 0; i2 < nRootsX2; ++i2)
         {
            double x2 = rootsX2[i2];
            if (x2 < 0) continue;
            for (int i3 = 0; i3 < nRootsX3; ++i3)
            {
               double x3 = rootsX3[i3];
               if (x3 < 0) continue;
               double excess = fabs(x2*x2 + x3*x3 - 2*x2*x3*c23 - d23*d23);
               if (excess < bestExcess)
               {
                  bestExcess = excess;
                  bestX2 = x2;
                  bestX3 = x3;
               } // end if
            } // end for (i3)
         } // end for (i2)

         // Now we have found 3 depths.
         vector<Vector3d> leftPoints(3), rightPoints(3);
         leftPoints[0] = X1;
         leftPoints[1] = X2;
         leftPoints[2] = X3;
         rightPoints[0] = x1 * u1;
         rightPoints[1] = bestX2 * u2;
         rightPoints[2] = bestX3 * u3;

         Matrix3x3d R;
         Vector3d T;
         getEuclideanTransformation(leftPoints, rightPoints, R, T);
         copyMatrixSlice(R, 0, 0, 3, 3, RTs[numRTs], 0, 0);
         RTs[numRTs].setColumnSlice(0, 3, 3, T);
         numRTs++;
         if(numRTs==maxRTs)
             return;
      } // end for (i)
   } // end computeAbsolutePose3Point()

   bool
   refineAbsolutePose(std::vector<Vector2f> const& normalizedPoints2d, std::vector<Vector3d> const& points3d,
                      double inlierThreshold, Matrix3x3d& R, Vector3d& T)
   {
      if (points3d.size() < 3)
         throwV3DErrorHere("V3D::refineAbsolutePose(): absolute pose requires 3 correspondences.");
      if (normalizedPoints2d.size() != points3d.size())
         throwV3DErrorHere("V3D::refineAbsolutePose(): mismatch in number of 3d and 2d points.");

      AbsolutePoseMinimizer opt(normalizedPoints2d, points3d, inlierThreshold);

      opt._currentR = R;
      opt._currentT = T;

      opt.minimize();

      R = opt._currentR;
      T = opt._currentT;

      return true;
   } // end refineAbsolutePose()

} // end namespace V3D
